C#でXMLを処理する方法


85

C#2.0でXMLドキュメントやXSDなどを処理するための最良の方法は何ですか?

どのクラスを使用するかなど。XMLドキュメントの解析と作成などのベストプラクティスは何ですか。

編集:.Net3.5の提案も歓迎します。


より実行可能な解決策を見つけようとしている人にとっては、これを無視してください。古い.NETライブラリです。使用XDocument代わりに、あなたは欲求不満であなたの目をえぐり救う
AER

回答:


177

C#2.0での読み取りと書き込みの主な手段は、XmlDocumentクラスを介して行われます。ほとんどの設定は、受け入れるXmlReaderを介してXmlDocumentに直接ロードできます。

XMLを直接ロードする

XmlDocument document = new XmlDocument();
document.LoadXml("<People><Person Name='Nick' /><Person Name='Joe' /></People>");

ファイルからのXMLのロード

XmlDocument document = new XmlDocument();
document.Load(@"C:\Path\To\xmldoc.xml");
// Or using an XmlReader/XmlTextReader
XmlReader reader = XmlReader.Create(@"C:\Path\To\xmldoc.xml");
document.Load(reader);

XMLドキュメントを読む最も簡単で速い方法は、XPathを使用することです。

XPathを使用したXMLドキュメントの読み取り(編集を可能にするXmlDocumentを使用)

XmlDocument document = new XmlDocument();
document.LoadXml("<People><Person Name='Nick' /><Person Name='Joe' /></People>");

// Select a single node
XmlNode node = document.SelectSingleNode("/People/Person[@Name = 'Nick']");

// Select a list of nodes
XmlNodeList nodes = document.SelectNodes("/People/Person");

XSDドキュメントを操作してXMLドキュメントを検証する必要がある場合は、これを使用できます。

XSDスキーマに対するXMLドキュメントの検証

XmlReaderSettings settings = new XmlReaderSettings();
settings.ValidateType = ValidationType.Schema;
settings.Schemas.Add("", pathToXsd); // targetNamespace, pathToXsd

XmlReader reader = XmlReader.Create(pathToXml, settings);
XmlDocument document = new XmlDocument();

try {
    document.Load(reader);
} catch (XmlSchemaValidationException ex) { Trace.WriteLine(ex.Message); }

各ノードでのXSDに対するXMLの検証(更新1)

XmlReaderSettings settings = new XmlReaderSettings();
settings.ValidateType = ValidationType.Schema;
settings.Schemas.Add("", pathToXsd); // targetNamespace, pathToXsd
settings.ValidationEventHandler += new ValidationEventHandler(settings_ValidationEventHandler);

XmlReader reader = XmlReader.Create(pathToXml, settings);
while (reader.Read()) { }

private void settings_ValidationEventHandler(object sender, ValidationEventArgs args)
{
    // e.Message, e.Severity (warning, error), e.Error
    // or you can access the reader if you have access to it
    // reader.LineNumber, reader.LinePosition.. etc
}

XMLドキュメントの作成(手動)

XmlWriter writer = XmlWriter.Create(pathToOutput);
writer.WriteStartDocument();
writer.WriteStartElement("People");

writer.WriteStartElement("Person");
writer.WriteAttributeString("Name", "Nick");
writer.WriteEndElement();

writer.WriteStartElement("Person");
writer.WriteStartAttribute("Name");
writer.WriteValue("Nick");
writer.WriteEndAttribute();
writer.WriteEndElement();

writer.WriteEndElement();
writer.WriteEndDocument();

writer.Flush();

(更新1)

.NET 3.5では、XDocumentを使用して同様のタスクを実行します。ただし、違いは、Linqクエリを実行して必要なデータを正確に選択できるという利点があることです。オブジェクト初期化子を追加すると、クエリ自体で独自の定義のオブジェクトを返すクエリを作成できます。

    XDocument doc = XDocument.Load(pathToXml);
    List<Person> people = (from xnode in doc.Element("People").Elements("Person")
                       select new Person
                       {
                           Name = xnode.Attribute("Name").Value
                       }).ToList();

(更新2)

.NET 3.5の優れた方法は、XDocumentを使用してXMLを作成することです。これにより、コードが目的の出力と同様のパターンで表示されます。

XDocument doc =
        new XDocument(
              new XDeclaration("1.0", Encoding.UTF8.HeaderName, String.Empty),
              new XComment("Xml Document"),
              new XElement("catalog",
                    new XElement("book", new XAttribute("id", "bk001"),
                          new XElement("title", "Book Title")
                    )
              )
        );

作成します

<!--Xml Document-->
<catalog>
  <book id="bk001">
    <title>Book Title</title>
  </book>
</catalog>

他のすべてが失敗した場合は、ここで説明した多くの例などがあるこのMSDNの記事を確認してください。 http://msdn.microsoft.com/en-us/library/aa468556.aspx


3
XDocumentはXmlDocumentとはかなり異なるため、最後の例でXDocumentを使用していることを指摘しておくとよいでしょう
Aaron Powell

2
補正; C#3.5はありません。
つまり

ああ、そして「オンザフライ」[オブジェクト初期化子]はC#3.0とXmlDocumentでほぼ同じように機能します-それでも良い答えですが(+1)
MarcGravell

XPathでクエリを実行する(編集しない)ドキュメントをロードする場合は、XPathDocumentを使用する方がはるかに効率的であることに注意してください
Oliver Hallam

このスキーマ検証はノードごとに行われますか?そうでない場合、ノードごとにそれを行う方法はありますか?
Malik Daud Ahmad Khokhar

30

サイズによって異なります。中小規模のxmlの場合、XmlDocument(任意のC#/。NETバージョン)やXDocument(.NET 3.5 / C#3.0)などのDOMが明らかに勝者です。XSDを使用するために、あなたは使用してXMLを読み込むことができたXmlReaderを、およびXmlReaderのは(して受け入れ作成XmlReaderSettingsを。XmlReaderSettingsオブジェクトには、xsd(またはdtd)検証を実行するために使用できるSchemasプロパティがあります。

xmlの記述についても同じことが当てはまりますが、LINQ-to-XML(XDocument)を使用してコンテンツをレイアウトする方が古いXmlDocumentよりも少し簡単であることに注意してください。

ただし、巨大なxmlの場合、DOMが大量のメモリを消費する可能性があります。その場合、XmlReader / XmlWriterを直接使用する必要があります。

最後に、xmlを操作するために、XslCompiledTransform(xsltレイヤー)を使用することをお勧めします。

xmlを操作する代わりに、オブジェクトモデルを操作することもできます。あなたが使用することができますXsd.exeではをXSDに準拠したモデルを表すクラスを作成し、単純にXMLをロードするオブジェクトとして、オブジェクト指向とそれを操作して、再度、これらのオブジェクトをシリアル化。これはXmlSerializerで行います


大きなXMLドキュメント(40k行)を操作(要素の追加/サポート)します。最善の方法は何ですか?以前はLINQ-to-XMLを使用していました。
Neyoh 2016年

12

nyxtomの答えはとても良いです。私はそれにいくつかのことを追加します:

XMLドキュメントへの読み取り専用アクセスが必要な場合XPathDocumentは、よりもはるかに軽量なオブジェクトですXmlDocument

使用しての欠点はXPathDocument、使い慣れ使用できないということであるSelectNodesSelectSingleNodeの方法をXmlNode。代わりに、IXPathNavigable提供されているツールを使用する必要があります。を使用してCreateNavigatorを作成しXPathNavigator、を使用してXPathNavigatorを作成XPathNodeIteratorし、XPathを介して見つけたノードのリストを反復処理します。これには通常、XmlDocumentメソッドよりも数行多くのコードが必要です。

ただし、XmlDocumentおよびXmlNodeクラスはを実装IXPathNavigableするため、でこれらのメソッドを使用するために記述したコードXPathDocumentは、でも機能しますXmlDocument。に対して書くことに慣れている場合IXPathNavigable、メソッドはどちらのオブジェクトに対しても機能します。(これが、メソッドシグネチャの使用XmlNodeXmlDocumentinでFxCopによってフラグが立てられる理由です。)

嘆かわしい、XDocumentおよびXElement(とXNodeXObject)を実装していませんIXPathNavigable

nyxtomの答えに存在しないもう1つのことはXmlReaderです。通常はXmlReader、XMLストリームの処理を開始する前に、XMLストリームをオブジェクトモデルに解析するオーバーヘッドを回避するために使用します。代わりに、を使用して、XmlReader一度に1つのXMLノードで入力ストリームを処理します。これは本質的にSAXに対する.NETの答えです。これにより、非常に大きなXMLドキュメントを処理するための非常に高速なコードを記述できます。

XmlReader また、XMLドキュメントフラグメントを処理する最も簡単な方法を提供します。たとえば、SQLServerのFORXMLRAWオプションが返す包含要素のないXML要素のストリームです。

使用して作成するコードXmlReaderは、通常、読み取るXMLの形式と非常に緊密に結合されています。XPathを使用すると、コードをXMLにはるかに疎結合することができます。これが、一般的に正しい答えである理由です。しかし、使用する必要があるときはXmlReader、本当に必要です。


3
from (派生クラスを含む)XPathNavigator CreateNavigator(this XNode node)を作成するための拡張メソッドがあることに注意してください。XPathNavigatorXNodeXDocument
デイブ

5

まず、新しいXDocumentクラスとXElementクラスについて理解します。これらは、以前のXmlDocumentファミリよりも改善されているためです。

  1. LINQで動作します
  2. 彼らはより速くそしてより軽量です

ただし、レガシーコード(特に以前に生成されたプロキシ)を操作するには、古いクラスを使用する必要がある場合があります。その場合、これらのXML処理クラス間で相互運用するためのいくつかのパターンに精通する必要があります。

あなたの質問は非常に広範で、詳細を説明するために1つの回答で多くを必要とするだろうと思いますが、これは私が考えた最初の一般的な回答であり、出発点として役立ちます。


私はそれら(XDocumentなど)が素晴らしいことに同意しますが、OPはC#2.0について尋ねました。
MarcGravell


2

.NET 3.5で作業していて、実験的なコードに不満がない場合は、LINQ to XSD(http://blogs.msdn.com/xmlteam/archive/2008/02/21/linq-to-)を確認できます。xsd-alpha-0-2.aspx)。これは、XSDから.NETクラスを生成します(XSDからの組み込みルールを含む)。

次に、ファイルに直接書き込んだり、ファイルから読み取ったりして、XSDルールに準拠していることを確認できます。

使用するXMLドキュメントにXSDを使用することを強くお勧めします。

  • XMLでルールを適用できます
  • XMLがどのように構成されているか/構造化されるかを他の人が確認できるようにします
  • XMLの検証に使用できます

Liquid XML StudioはXSDを生成するための優れたツールであり、無料であることがわかりました。


2

XmlDocumentクラスを使用したXMLの記述

//itemValues is collection of items in Key value pair format
//fileName i name of XML file which to creatd or modified with content
    private void WriteInXMLFile(System.Collections.Generic.Dictionary<string, object> itemValues, string fileName)
    {
        string filePath = "C:\\\\tempXML\\" + fileName + ".xml";
        try
        {

            if (System.IO.File.Exists(filePath))
            {
                XmlDocument doc = new XmlDocument();
                doc.Load(filePath);                   

                XmlNode rootNode = doc.SelectSingleNode("Documents");

                XmlNode pageNode = doc.CreateElement("Document");
                rootNode.AppendChild(pageNode);


                foreach (string key in itemValues.Keys)
                {

                    XmlNode attrNode = doc.CreateElement(key);
                    attrNode.InnerText = Convert.ToString(itemValues[key]);
                    pageNode.AppendChild(attrNode);
                    //doc.DocumentElement.AppendChild(attrNode);

                }
                doc.DocumentElement.AppendChild(pageNode);
                doc.Save(filePath);
            }
            else
            {
                XmlDocument doc = new XmlDocument();
                using(System.IO.FileStream fs = System.IO.File.Create(filePath))
                {
                    //Do nothing
                }

                XmlNode rootNode = doc.CreateElement("Documents");
                doc.AppendChild(rootNode);
                doc.Save(filePath);

                doc.Load(filePath);

                XmlNode pageNode = doc.CreateElement("Document");
                rootNode.AppendChild(pageNode);

                foreach (string key in itemValues.Keys)
                {                          
                    XmlNode attrNode = doc.CreateElement(key);                           
                    attrNode.InnerText = Convert.ToString(itemValues[key]);
                    pageNode.AppendChild(attrNode);
                    //doc.DocumentElement.AppendChild(attrNode);

                }
                doc.DocumentElement.AppendChild(pageNode);

                doc.Save(filePath);

            }
        }
        catch (Exception ex)
        {

        }

    }

OutPut look like below
<Dcouments>
    <Document>
        <DocID>01<DocID>
        <PageName>121<PageName>
        <Author>Mr. ABC<Author>
    <Dcoument>
    <Document>
        <DocID>02<DocID>
        <PageName>122<PageName>
        <Author>Mr. PQR<Author>
    <Dcoument>
</Dcouments>

1

デザイナで型付きデータセットを作成すると、強く型付けされたオブジェクトであるxsdが自動的に取得され、1行のコードでxmlを読み込んで保存できます。


私はDataSetで大成功を収めました。彼らはまたデータベースと非常に友好的です。
user1

1

C#プログラマーとしての私の個人的な意見は、C#でXMLを処理する最良の方法は、コードのその部分をVB.NETプロジェクトに委任することです。.NET 3.5では、VB .NETにXMLリテラルがあり、XMLの処理がはるかに直感的になります。たとえば、ここを参照してください。

VisualBasicでのLINQtoXMLの概要

(C#コードではなく、VBコードを表示するようにページを設定してください。)

プロジェクトの残りの部分はC#で記述しますが、参照されるVBプロジェクトでXMLを処理します。


XMLリテラルの場合のみvbに切り替える価値はありません。XMLはリテラルのみを扱います。xmlがパラメーターとして渡される場合、XMLリテラルのサポートはあまりメリットがありません。代わりに、vb.netのレガシー構文は、C#の幸せなプログラミング体験を台無しにします。
gqqnbig 2017年

0

nyxtom、

例1で「doc」と「xdoc」を一致させるべきではありませんか?

XDocument **doc** = XDocument.Load(pathToXml);
List<Person> people = (from xnode in **xdoc**.Element("People").Elements("Person")
                   select new Person
                   {
                       Name = xnode.Attribute("Name").Value
                   }).ToList();

あなたが参照している回答の承認のために編集を提出しましたが、これは実際には回答ではなくコメントであるはずです。
デビッドトンプソン

デビッドに感謝します。同意しました、それは私がその時にコメントすることを許さないでしょう。理由はわかりません。
mokumaxCraig 2014

0

Cookeyの答えは良いです...しかし、XSD(またはXML)から厳密に型指定されたオブジェクトを作成し、数行のコードでシリアル化/逆シリアル化する方法の詳細な手順は次のとおりです。

指示


「探していたページは存在しません。」:(
Ian Grainger

0

XmlNode<=> XNode<=>間でデータを変換する必要がある場合XElement
(たとえば、LINQを使用するため)、この拡張機能が役立つ場合があります。

public static class MyExtensions
{
    public static XNode GetXNode(this XmlNode node)
    {
        return GetXElement(node);
    }

    public static XElement GetXElement(this XmlNode node)
    {
        XDocument xDoc = new XDocument();
        using (XmlWriter xmlWriter = xDoc.CreateWriter())
            node.WriteTo(xmlWriter);
        return xDoc.Root;
    }

    public static XmlNode GetXmlNode(this XElement element)
    {
        using (XmlReader xmlReader = element.CreateReader())
        {
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load(xmlReader);
            return xmlDoc;
        }
    }

    public static XmlNode GetXmlNode(this XNode node)
    {
        return GetXmlNode(node);
    }
}

使用法:

XmlDocument MyXmlDocument = new XmlDocument();
MyXmlDocument.Load("MyXml.xml");
XElement MyXElement = MyXmlDocument.GetXElement(); // Convert XmlNode to XElement
List<XElement> List = MyXElement.Document
   .Descendants()
   .ToList(); // Now you can use LINQ
...
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.