【问题标题】:How to deal with XML in C#如何在 C# 中处理 XML
【发布时间】:2010-09-18 06:20:30
【问题描述】:

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

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

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

【问题讨论】:

  • 对于那些也试图找到更可行的解决方案的人,请忽略这一点。这是一个旧的 .NET 库。改用 XDocument,这样您就不会因为沮丧而睁大眼睛了

标签: c# .net xml


【解决方案1】:

在 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

【讨论】:

  • 您可能想指出您在最后一个示例中使用的是 XDocument,因为 XDocument 与 XmlDocument 完全不同
  • 更正;没有 C# 3.5;你的意思是 .NET 3.5 和 C# 3.0
  • 哦,“on the fly” [object initializers] 与 C# 3.0 和 XmlDocument 的工作方式基本相同——尽管 (+1) 仍然是一个很好的答案
  • 值得一提的是,如果您正在加载一个文档以使用 XPath 进行查询(而不是编辑),那么使用 XPathDocument 会更有效率
  • 此模式验证是否逐个节点完成?如果没有,有没有办法逐个节点?
【解决方案2】:

这取决于大小;对于中小型 xml,诸如 XmlDocument(任何 C#/.NET 版本)或 XDocument(.NET 3.5/C# 3.0)之类的 DOM 是明显的赢家。对于使用 xsd,您可以使用 XmlReader 加载 xml,并且 XmlReader 接受(到 CreateXmlReaderSettings。 XmlReaderSettings 对象有一个 Schemas 属性,可用于执行 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。
【解决方案3】:

nyxtom 的回答非常好。我会添加一些东西:

如果您需要对 XML 文档进行只读访问,XPathDocument 是一个比 XmlDocument 轻得多的对象。

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

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

遗憾的是,XDocumentXElement(以及 XNodeXObject)没有实现 IXPathNavigable

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

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

您使用XmlReader 编写的代码通常与它正在读取的XML 格式紧密耦合。使用 XPath 可以让您的代码与 XML 更松散地耦合,这就是为什么它通常是正确答案的原因。但是当你需要使用XmlReader时,你真的需要它。

【讨论】:

【解决方案4】:

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

  1. 他们使用 LINQ
  2. 它们更快、更轻便

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

我认为您的问题相当广泛,需要在一个答案中提供太多细节才能提供详细信息,但这是我想到的第一个一般性答案,并且可以作为一个开始。

【讨论】:

  • 我同意他们(XDocument 等)很棒,但 OP 询问了 C# 2.0。
【解决方案5】:

101 个 Linq 样本

http://msdn.microsoft.com/en-us/library/bb387098.aspx

Linq to XML 示例

http://msdn.microsoft.com/en-us/vbasic/bb688087.aspx

而且我认为 Linq 让 XML 变得简单。

【讨论】:

    【解决方案6】:

    如果您使用 .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 的绝佳工具,而且它是免费的!

    【讨论】:

      【解决方案7】:

      使用 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>
      

      【讨论】:

        【解决方案8】:

        如果你在设计器中创建了一个类型化的数据集,那么你会自动得到一个 xsd,一个强类型的对象,并且可以通过一行代码加载和保存 xml。

        【讨论】:

        • 我在 DataSet 方面取得了巨大成功。他们对数据库也非常友好。
        【解决方案9】:

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

        Overview of LINQ to XML in Visual Basic

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

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

        【讨论】:

        • 只为 XML 文字切换到 vb 是不值得的。 XML 只处理文字。如果 xml 作为参数传入,XML 文字支持不会给您带来太多好处。相反,vb.net 的遗留语法会破坏 C# 愉快的编程体验。
        【解决方案10】:

        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();
        

        【讨论】:

        • 我已经提交了您所指答案的编辑以供批准,但这应该是评论,而不是答案。
        • 谢谢大卫。同意,当时不允许我发表评论。不知道为什么。
        【解决方案11】:

        Cookey 的回答很好……但这里有关于如何从 XSD(或 XML)创建强类型对象并在几行代码中序列化/反序列化的详细说明:

        Instructions

        【讨论】:

        • "您要查找的页面不存在。" :(
        【解决方案12】:

        如果您需要在 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
        ...
        

        【讨论】:

          猜你喜欢
          • 2015-11-04
          • 1970-01-01
          • 2021-01-23
          • 1970-01-01
          • 2012-06-22
          • 2020-12-14
          • 1970-01-01
          • 2013-06-24
          • 1970-01-01
          相关资源
          最近更新 更多