简体   繁体   English

如何在C#中处理XML

[英]How to deal with XML in C#

What is the best way to deal with XML documents, XSD etc in C# 2.0? 在C#2.0中处理XML文档,XSD等的最佳方法是什么?

Which classes to use etc. What are the best practices of parsing and making XML documents etc. 使用哪些类等。解析和制作XML文档等的最佳实践是什么?

EDIT: .Net 3.5 suggestions are also welcome. 编辑:.Net 3.5建议也欢迎。

The primary means of reading and writing in C# 2.0 is done through the XmlDocument class. C#2.0中读写的主要方法是通过XmlDocument类完成的。 You can load most of your settings directly into the XmlDocument through the XmlReader it accepts. 您可以通过它接受的XmlReader将大部分设置直接加载到XmlDocument中。

Loading XML Directly 直接加载XML

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

Loading XML From a File 从文件加载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);

I find the easiest/fastest way to read an XML document is by using XPath. 我发现使用XPath读取XML文档最简单/最快捷的方法。

Reading an XML Document using XPath (Using XmlDocument which allows us to edit) 使用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");

If you need to work with XSD documents to validate an XML document you can use this. 如果需要使用XSD文档来验证XML文档,可以使用它。

Validating XML Documents against XSD Schemas 根据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); }

Validating XML against XSD at each Node (UPDATE 1) 在每个节点上针对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
}

Writing an XML Document (manually) 编写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();

(UPDATE 1) (更新1)

In .NET 3.5, you use XDocument to perform similar tasks. 在.NET 3.5中,您使用XDocument执行类似的任务。 The difference however is you have the advantage of performing Linq Queries to select the exact data you need. 但不同之处在于,您可以通过执行Linq查询来选择所需的确切数据。 With the addition of object initializers you can create a query that even returns objects of your own definition right in the query itself. 通过添加对象初始值设定项,您可以创建一个查询,甚至可以在查询本身中返回您自己定义的对象。

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

(UPDATE 2) (更新2)

A nice way in .NET 3.5 is to use XDocument to create XML is below. .NET 3.5中的一个很好的方法是使用XDocument来创建XML。 This makes the code appear in a similar pattern to the desired output. 这使得代码以与所需输出类似的模式显示。

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

creates 创建

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

All else fails, you can check out this MSDN article that has many examples that I've discussed here and more. 所有其他方法都失败了,你可以查看这篇MSDN文章,其中有很多我在这里讨论的例子以及更多。 http://msdn.microsoft.com/en-us/library/aa468556.aspx http://msdn.microsoft.com/en-us/library/aa468556.aspx

It depends on the size; 这取决于大小; for small to mid size xml, a DOM such as XmlDocument (any C#/.NET versions) or XDocument (.NET 3.5/C# 3.0) is the obvious winner. 对于中小型xml,诸如XmlDocument (任何C#/ .NET版本)或XDocument (.NET 3.5 / C#3.0)之类的DOM显然是赢家。 For using xsd, You can load xml using an XmlReader , and an XmlReader accepts (to Create ) an XmlReaderSettings . 对于使用xsd,您可以使用XmlReader加载xml,XmlReader接受( 创建XmlReaderSettings The XmlReaderSettings objects has a Schemas property that can be used to perform xsd (or dtd) validation. XmlReaderSettings对象具有Schemas属性,可用于执行xsd(或dtd)验证。

For writing xml, the same things apply, noting that it is a little easier to lay out content with LINQ-to-XML (XDocument) than the older XmlDocument. 对于编写xml,同样适用,注意使用LINQ-to-XML(XDocument)布局内容比使用旧版XmlDocument要容易一些。

However, for huge xml, a DOM may chomp too much memory, in which case you might need to use XmlReader/XmlWriter directly. 但是,对于巨大的xml,DOM可能会占用太多内存,在这种情况下,您可能需要直接使用XmlReader / XmlWriter。

Finally, for manipulating xml you may wish to use XslCompiledTransform (an xslt layer). 最后,对于操作xml,您可能希望使用XslCompiledTransform (xslt层)。

The alternative to working with xml is to work with an object model; 使用xml的替代方法是使用对象模型; you can use xsd.exe to create classes that represent an xsd-compliant model, and simply load the xml as objects , manipulate it with OO, and then serialize those objects again; 您可以使用xsd.exe创建表示符合xsd的模型的类,只需将xml 作为对象加载,使用OO操作它,然后再次序列化这些对象; you do this with XmlSerializer . 你用XmlSerializer做到这一点。

nyxtom's answer is very good. nyxtom的答案非常好。 I'd add a couple of things to it: 我要添加一些东西:

If you need read-only access to an XML document, XPathDocument is a much lighter-weight object than XmlDocument . 如果您需要对XML文档的只读访问权限,则XPathDocument是一个比XmlDocument轻得多的对象。

The downside of using XPathDocument is that you can't use the familiar SelectNodes and SelectSingleNode methods of XmlNode . 使用XPathDocument的缺点是您不能使用XmlNode熟悉的SelectNodesSelectSingleNode方法。 Instead, you have to use the tools that the IXPathNavigable provides: use CreateNavigator to create an XPathNavigator , and use the XPathNavigator to create XPathNodeIterator s to iterate over the lists of nodes you find via XPath. 相反,您必须使用IXPathNavigable提供的工具:使用CreateNavigator创建XPathNavigator ,并使用XPathNavigator创建XPathNodeIterator以迭代通过XPath找到的节点列表。 This generally requires a few more lines of code than the XmlDocument methods. 这通常需要比XmlDocument方法多几行代码。

But: the XmlDocument and XmlNode classes implement IXPathNavigable , so any code you write to use those methods on an XPathDocument will also work on an XmlDocument . 但是: XmlDocumentXmlNode类实现IXPathNavigable ,因此您在XPathDocument上使用这些方法编写的任何代码也可以在XmlDocument If you get used to writing against IXPathNavigable , your methods can work against either object. 如果您习惯于对IXPathNavigable进行编写, IXPathNavigable您的方法可以对任一对象起作用。 (This is why using XmlNode and XmlDocument in method signatures is flagged by FxCop.) (这就是为什么在方法签名中使用XmlNodeXmlDocument会被FxCop标记的原因。)

Lamentably, XDocument and XElement (and XNode and XObject ) don't implement IXPathNavigable . 可悲的是, XDocumentXElement (以及XNodeXObject )没有实现IXPathNavigable

Another thing not present in nyxtom's answer is XmlReader . nyxtom的答案中没有的另一件事是XmlReader You generally use XmlReader to avoid the overhead of parsing the XML stream into an object model before you begin processing it. 在开始处理XML流之前,通常使用XmlReader来避免将XML流解析为对象模型的开销。 Instead, you use an XmlReader to process the input stream one XML node at a time. 相反,您使用XmlReader处理一个XML节点的输入流。 This is essentially .NET's answer to SAX. 这基本上是.NET对SAX的回答。 It lets you write very fast code for processing very large XML documents. 它允许您编写非常快速的代码来处理非常大的XML文档。

XmlReader also provides the simplest way of processing XML document fragments, eg the stream of XML elements with no encluding element that SQL Server's FOR XML RAW option returns. XmlReader还提供了处理XML文档片段的最简单方法,例如XML元素流,没有SQL Server的FOR XML RAW选项返回的包含元素。

The code you write using XmlReader is generally very tightly coupled to the format of the XML it's reading. 使用XmlReader编写的代码通常与它正在阅读的XML格式紧密耦合。 Using XPath allows your code to be much, much more loosely coupled to the XML, which is why it's generally the right answer. 使用XPath可以使代码与XML更加松散地耦合,这就是为什么它通常是正确的答案。 But when you need to use XmlReader , you really need it. 但是当你需要使用XmlReader ,你真的需要它。

First of all, get to know the new XDocument and XElement classes, because they are an improvement over the previous XmlDocument family. 首先,了解新的XDocumentXElement类,因为它们是对以前的XmlDocument系列的改进。

  1. They work with LINQ 他们使用LINQ
  2. They are faster and more lightweight 它们更快,更轻巧

However , you may have to still use the old classes to work with legacy code - particularly previously generated proxies. 但是 ,您可能仍必须使用旧类来处理遗留代码 - 特别是以前生成的代理。 In that case, you will need to become familiar with some patterns for interoperating between these XML-handling classes. 在这种情况下,您需要熟悉这些XML处理类之间的互操作模式。

I think your question is quite broad, and would require too much in a single answer to give details, but this is the first general answer I thought of, and serves as a start. 我认为你的问题相当广泛,并且在一个答案中需要过多提供细节,但这是我想到的第一个一般性答案,并作为一个开始。

101 Linq samples 101 Linq样本

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

and Linq to XML samples Linq到XML样本

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

And I think Linq makes XML easy. 我认为Linq使XML变得简单。

If you're working in .NET 3.5 and you aren't affraid of experimental code you can check out LINQ to XSD ( http://blogs.msdn.com/xmlteam/archive/2008/02/21/linq-to-xsd-alpha-0-2.aspx ) which will generate .NET classes from an XSD (including built in rules from the XSD). 如果你在.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的内置规则)。

It then has the ability to write straight out to a file and read from a file ensuring that it conforms to the XSD rules. 然后它可以直接写入文件并从文件中读取,确保它符合XSD规则。

I definately suggest having an XSD for any XML document you work with: 我肯定建议您使用任何XML文档的XSD:

  • Allows you to enforce rules in the XML 允许您在XML中强制执行规则
  • Allows others to see how the XML is/ will be structured 允许其他人查看XML的结构/结构
  • Can be used for validation of XML 可用于验证XML

I find that Liquid XML Studio is a great tool for generating XSD's and it's free! 我发现Liquid XML Studio是一个很好的生成XSD的工具,它是免费的!

如果在设计器中创建类型化数据集,则会自动获取xsd(强类型对象),并可以使用一行代码加载和保存xml。

My personal opinion, as a C# programmer, is that the best way to deal with XML in C# is to delegate that part of the code to a VB .NET project. 我个人认为,作为C#程序员,在C#中处理XML的最佳方法是将该部分代码委托给VB .NET项目。 In .NET 3.5, VB .NET has XML Literals, which make dealing with XML much more intuitive. 在.NET 3.5中,VB .NET具有XML Literals,这使得处理XML更加直观。 See here, for example: 见这里,例如:

Overview of LINQ to XML in Visual Basic Visual Basic中LINQ to XML概述

(Be sure to set the page to display VB code, not C# code.) (务必将页面设置为显示VB代码,而不是C#代码。)

I'd write the rest of the project in C#, but handle the XML in a referenced VB project. 我用C#编写了项目的其余部分,但是在引用的VB项目中处理XML。

Writing XML with the XmlDocument class 使用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>

Cookey's answer is good... but here are detailed instructions on how to create a strongly typed object from an XSD(or XML) and serialize/deserialize in a few lines of code: Cookey的答案很好......但是这里有关于如何从XSD(或XML)创建强类型对象以及在几行代码中序列化/反序列化的详细说明:

Instructions 说明

nyxtom, nyxtom,

Shouldn't "doc" and "xdoc" match in Example 1? 示例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();

If you ever need to convert data between XmlNode <=> XNode <=> XElement 如果您需要在XmlNode <=> XNode <=> XElement之间转换数据
(eg in order to use LINQ) this Extensions may be helpful for you: (例如,为了使用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);
    }
}

Usage: 用法:

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
...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM