如何在C#中处理XML


85

在C#2.0中处理XML文档,XSD等的最佳方法是什么?

使用哪些类等。解析和制作XML文档等的最佳实践是什么。

编辑:.Net 3.5建议也欢迎。


对于那些还试图找到更可行的解决方案的人,请忽略此。它是一个旧的.NET库。使用的XDocument相反,你会节省剜你的眼睛在挫折
AER

Answers:


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,因为XDocument与XmlDocument完全不同
Aaron Powell,

2
更正; 没有C#3.5;您是说.NET 3.5和C#3.0
Marc Gravell

哦,“运行中的” [对象初始值设定项]与C#3.0和XmlDocument大致相同,尽管(+1)
Marc Gravell

可能值得一提的是,如果您正在加载文档以使用XPath查询(而不是进行编辑),那么使用XPathDocument会效率更高
Oliver Hallam'Oct

该架构验证是否逐节点完成?如果没有,有没有办法逐个节点地做呢?
Malik Daud Ahmad Khokhar,

30

这取决于大小。对于中小型xml,明显的赢家是诸如XmlDocument(任何C#/。NET版本)或XDocument(.NET 3.5 / C#3.0)之类的DOM 。对于使用xsd,可以使用XmlReader加载xml ,并且XmlReader接受(创建XmlReaderSettings。XmlReaderSettings对象具有一个架构属性,可用于执行xsd(或dtd)验证。

对于编写xml,同样适用,要注意的是,使用LINQ-to-XML(XDocument)布置内容比旧的XmlDocument要容易一些。

但是,对于庞大的xml,DOM可能会占用过多的内存,在这种情况下,您可能需要直接使用XmlReader / XmlWriter。

最后,要处理xml,您可能希望使用XslCompiledTransform(xslt层)。

使用xml的替代方法是使用对象模型。您可以使用xsd.exe创建代表兼容xsd的模型的类,只需将xml加载为对象,使用OO对其进行操作,然后再次序列化这些对象;您可以使用XmlSerializer进行此操作。


操纵(添加/添加元素)一个大的XML文档(40k行)。最好的方法是什么?我曾经使用LINQ-to-XML。
Neyoh

12

nyxtom的答案很好。我要添加一些内容:

如果您需要对XML文档的只读访问权限,XPathDocument则该对象的重量要轻得多XmlDocument

使用的缺点XPathDocument是您不能使用熟悉的SelectNodesSelectSingleNode方法XmlNode。相反,您必须使用提供的工具IXPathNavigable:使用CreateNavigator创建一个XPathNavigator,并使用XPathNavigator创建XPathNodeIterator一个来遍历通过XPath找到的节点列表。与XmlDocument方法相比,这通常需要多几行代码。

但是:XmlDocumentXmlNode类实现了IXPathNavigable,因此您编写的用于在上使用这些方法的任何代码XPathDocument也可以在上使用XmlDocument。如果您习惯针对编写IXPathNavigable,则您的方法可以针对任一对象。(这就是FxCop标记使用XmlNodeXmlDocument方法签名的原因。)

可悲的是,XDocumentand XElement(和XNodeand XObject)没有实现IXPathNavigable

nyxtom的答案中没有出现的另一件事是XmlReader。通常XmlReader,您可以避免在开始处理XML流之前将其解析为对象模型的开销。相反,您可以使用XmlReader来一次处理一个XML节点的输入流。从本质上讲,这是.NET对SAX的回答。它使您可以编写非常快速的代码来处理非常大的XML文档。

XmlReader 它还提供了处理XML文档片段的最简单方法,例如,不包含SQL Server的FOR XML RAW选项返回的包含元素的XML元素流。

您编写的代码XmlReader通常与所读取的XML格式紧密相关。使用XPath可以使您的代码与XML紧密得多地耦合,这就是为什么它通常是正确的答案。但是,当您需要使用时XmlReader,您确实需要它。


3
请注意,有一个扩展方法XPathNavigator CreateNavigator(this XNode node)XPathNavigator从创建扩展名XNode(包括派生类XDocument)。
戴夫

5

首先,了解新 XDocumentXElement类,因为它们是对以前的XmlDocument系列的改进。

  1. 他们与LINQ合作
  2. 它们更快,更轻便

但是,您可能仍必须使用旧类来处理旧版代码-特别是以前生成的代理。在这种情况下,您将需要熟悉一些在这些XML处理类之间进行互操作的模式。

我认为您的问题涉及面很广,在单个答案中需要太多内容以提供详细信息,但这是我想到的第一个一般性答案,并且作为一个开始。


我同意它们(XDocument等)很棒,但是OP询问了C#2.0。
马克·格拉韦尔


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(一个强类型化的对象),并且可以用一行代码来加载和保存xml。


我在DataSet方面取得了巨大的成功。他们对数据库也非常友好。
User1

1

作为C#程序员,我个人的观点是,用C#处理XML的最佳方法是将那部分代码委托给VB .NET项目。在.NET 3.5中,VB .NET具有XML文字,使处理XML更加直观。例如,请参见此处:

Visual Basic中的LINQ to XML概述

(确保将页面设置为显示VB代码,而不是C#代码。)

我将用C#编写项目的其余部分,但在引用的VB项目中处理XML。


只为XML文字转换为vb是不值得的。XML仅处理文字。如果将xml作为参数传递,则XML文字支持不会给您带来太多好处。相反,vb.net的旧语法将破坏C#的令人满意的编程体验。
Gqqnbig

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
...
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.