如何在C#中处理XML

时间:2008-10-21 05:35:34

标签: c# .net xml

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

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

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

12 个答案:

答案 0 :(得分:170)

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

在每个节点(更新1)

上针对XSD验证XML
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

答案 1 :(得分:29)

取决于尺寸;对于中小型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执行此操作。

答案 2 :(得分:12)

nyxtom的答案非常好。我要添加一些东西:

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

使用XPathDocument的缺点是您无法使用SelectNodes的常见SelectSingleNodeXmlNode方法。相反,您必须使用IXPathNavigable提供的工具:使用CreateNavigator创建XPathNavigator,并使用XPathNavigator创建XPathNodeIterator来迭代通过XPath找到的节点列表。这通常需要比XmlDocument方法多几行代码。

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

可悲的是,XDocumentXElement(以及XNodeXObject)未实现IXPathNavigable

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

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

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

答案 3 :(得分:4)

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

  1. 他们使用LINQ
  2. 它们更快更轻盈
  3. 但是,您可能还必须使用旧类来处理遗留代码 - 特别是以前生成的代理。在这种情况下,您需要熟悉这些XML处理类之间的互操作模式。

    我认为你的问题相当广泛,并且在一个答案中需要过多提供细节,但这是我想到的第一个一般性答案,并作为一个开始。

答案 4 :(得分:4)

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变得容易。

答案 5 :(得分: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的工具,它是免费的!

答案 6 :(得分:1)

如果您在设计器中创建了一个类型化数据集,那么您将自动获得一个xsd,一个强类型对象,并且可以使用一行代码加载和保存xml。

答案 7 :(得分:1)

我个人认为,作为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。

答案 8 :(得分:1)

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

答案 9 :(得分:0)

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

Instructions

答案 10 :(得分: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();

答案 11 :(得分: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
...