zoukankan      html  css  js  c++  java
  • C#(6):Linq To XML:XElement、XDocument

    一、概述

    LINQ to XMLLINQ to XML 是一种启用了 LINQ 的内存 XML 编程接口,使用它,可以在 .NET Framework.NET Framework 编程语言中处理 XML。

    在使用LINQ to XML时需要添加System.Xml.Linq.dll的引用。

    • XElement类 表示XML元素,它是XContainer类的派生类,而XContainer类又派生于XNode类。一个元素就是一个节点。
      XElement是LINQ to XML最重要最基本的类之一,它包含所有创建和操作XML元素所必需的功能。通过它可以创建元素,添加和修改元素的属性,操作元素的内容等。
    • XAttribute类 用来处理属性,属性是与元素相关联的名称/值对。
    • XDocument类 提供了处理有效XML文档的方法,包括声明、注释和处理指令。XDocument类派生自XContainer类,可以有子节点。XML标准限值XDocument对象只包含单个XElement子节点,此节点作为根节点或跟元素。

    继承关系:

    XNode(抽象)类派生类有:XText、XComment、XDocumentType、XProcessingInstruction、XContainer

    XContainer(抽象)类派生类有:XElement、XDocument.

    二、加载XML文件

     1、从文件中输入XML数据

    //1、从URI中获取XML数据,支持本地路径和URL,支持对应枚举的设置
    XElement xe1 = XElement.Load(@"D:123.xml",LoadOptions.None);
    
    //2、从XmlReader中加载
    XmlReader xr = XmlReader.Create(@"D:123.xml");
    XElement xe2 = XElement.Load(xr);
    
    //3、从TextReader中获取数据
    TextReader reader = File.OpenText(@"D:123.xml");
    XElement xe3 = XElement.Load(reader);
    
    //4、从Stream中读取
    XElement xe4 = XElement.Load(new FileStream(@"D:123.xml", FileMode.Open, FileAccess.Read));

    2、从字符串中输入XML数据

    string xmlString = "<?xml version="1.0" encoding="utf-8"?><Persons><Person><Name>刘备</Name><Age>28</Age></Person></Persons>";
    XElement xe = XElement.Parse(xmlString, LoadOptions.SetLineInfo);

    三、生成XML元素或XML文档

     1、创建XML元素

    XElement xml =
            new XElement("Persons",
                new XElement("Person",
                    new XElement("Name", "刘备"),
                    new XElement("Age", "28")
                    ),
                new XElement("Person",
                    new XElement("Name", "关羽"),
                    new XElement("Age", "27")
                    )
                );
    xml.Save(@"D:123.xml");

    2、创建XML文档

    //创建处理指令
    XProcessingInstruction instruction = new XProcessingInstruction("xml-stylesheet","href="hello.css" type = "text/css"");
    //创建声明对象
    XDeclaration xDeclaration = new XDeclaration("1.0","GB2312","yes");
    //创建文档类型
    XDocumentType documentType = new XDocumentType("Person", null, "Person.dtd", null);
    //创建XmlCData数据
    XCData data = new XCData("<h1>神奇的刘备</h1>");
    //创建XDocument文档
    XDocument xDoc = new XDocument();
    XElement xml =
        new XElement("Persons",
            new XElement("Person",
                new XAttribute("Description", "此人龙凤之姿 天日之表;"),
                new XElement("Name", data),
                new XElement("Age", "28")
                ),
            new XElement("Person",
                new XElement("Name", "关羽"),
                new XElement("Age", "27")
                )
            );
    xDoc.Add(documentType);
    xDoc.Add(instruction);
    xDoc.Declaration = xDeclaration;
    xDoc.Add(xml);
    
    xDoc.Save(@"D:123.xml");

    3、Linq查询生成XML

    我们实例化一个book的集合

    Book[] books = new Book[] {
      new Book("Ajax in Action", "Manning", 2005),
      new Book("Windows Forms in Action", "Manning", 2006),
      new Book("RSS and Atom in Action", "Manning", 2006)
    };

    如果我们现在想将Year== 2006的集合创建成以下XML格式

    <books>
     <book title="Windows Forms in Action">
     <publisher>Manning</publisher>
     </book>
     <book title="RSS and Atom in Action">
     <publisher>Manning</publisher>
     </book>
    </books>

    采用linq方式

    XElement xml = new XElement("books",
      from book in books
      where book.Year == 2006
      select new XElement("book",
         new XAttribute("title", book.Title),
         new XElement("publisher", book.Publisher)
      )
    );
    // 显示这个XML
    Console.WriteLine(xml);

    传统方式

    XmlDocument doc = new XmlDocument();
    XmlElement root = doc.CreateElement("books");
    foreach (Book book in books)
    {
    if (book.Year == 2006)
      {
        XmlElement element = doc.CreateElement("book");
        element.SetAttribute("title", book.Title);
        XmlElement publisher = doc.CreateElement("publisher");
        publisher.InnerText = book.Publisher;
        element.AppendChild(publisher);
        root.AppendChild(element);
      }
    }
    doc.AppendChild(root);
    // 显示这个XML
    doc.Save(Console.Out);

    4、属性转出元素

    XML文件:

    <?xml version="1.0" encoding="utf-8" ?>
    <Root Data1="123" Data2="456">
      <Child1>Content</Child1>
    </Root>

    您可以编写一些过程代码以便从属性创建元素,然后删除属性

    linq方式:

    XElement root = XElement.Load("Data.xml");
    XElement newTree = new XElement("Root",
        root.Element("Child1"),
        from att in root.Attributes()
        select new XElement(att.Name, (string)att)
    );
    xml.Save(@"D:123.xml");

    传统方式:

    XElement root = XElement.Load("Data.xml");
    foreach (XAttribute att in root.Attributes()) {
        root.Add(new XElement(att.Name, (string)att));
    }
    root.Attributes().Remove();

    5、XmlDocument转换为XDocument

    XmlDocument doc = new XmlDocument();
    doc.LoadXml(xmlStr);   //xml字符串转成xml文档对象
    
    XDocument xdoc = doc.ToXDocument(); //xmldocument转成xdoccument 扩展方法
    var eventId = xdoc.Document.Root.Element("EventID"); //根节点下的eventid节点
    if (eventId != null)
    {
        MessageBox.Show(eventId.Value); //15
    }

    扩展方法

    public static class XmlDocumentExtensions
    {
        public static XDocument ToXDocument(this XmlDocument document)
        {
            return document.ToXDocument(LoadOptions.None);
        }
    
        public static XDocument ToXDocument(this XmlDocument document, LoadOptions options)
        {
            using (XmlNodeReader reader = new XmlNodeReader(document))
            {
                return XDocument.Load(reader, options);
            }
        }
    }

    四、XML数据的输出

     XElement有个Save,这个Save有多种重载,支持将XML数据输入到各处(文件地址,流,TextWriter,XmlWriter)。

    XElement xml =
        new XElement("Persons",
            new XElement("Person",
                new XElement("Name", "刘备"),
                new XElement("Age", "28")
                )
            );
    //1、输出到文件
    xml.Save(@"D:123.xml");
    //2、输出到TextWriter
    TextWriter tw = new StringWriter();
    //第二个参数SaveOptions枚举支持设置格式,缩进,保留无关重要的空白,去除重复命名空间
    xml.Save(tw, SaveOptions.None);
    Console.WriteLine(tw);
    //3、输出到Stream
    using (MemoryStream mem = new MemoryStream())
    {
        xml.Save(mem);
        Console.WriteLine(Encoding.UTF8.GetString(mem.ToArray()));
    }
    //4、输出到XmlWriter
    XmlWriter xw = XmlWriter.Create(@"D:LinqToXml.xml");
    xml.Save(xw);
    
    xw.Flush();

    五、查询

    • Element()  :获取当前XML元素的第一个具有指定名称的子元素
    • Elements() :获取当前XML元素的所有子元素,或具有指定名称的所有子元素,返回类型为IEnumerable<XElement>的可用LINQ进行查询的元素集合
    • Attribute():  获取当前XML元素的具有指定名称的属性
    • Attributes(): 获取当前XML元素的所有属性或者具有指定名称的属性, 返回类型为IEnumerable<XAttribute>的LINQ集合

    1、查询根元素

    IEnumerable<XElement> elements = from e in doc.Elements("Products")
                                     select e;
    foreach (XElement e in elements)
    {
        Console.WriteLine("{0}-{1}", e.Name, e.Value);
    }

    2、查询节点

    var query = from p in doc.Element("Products").Elements("Product")
                where (int)p.Element("ProductID") == 1
                orderby p.Attribute("ID").Value 
                select p;
    
    query.ToList().ForEach(item =>
    {
        Console.WriteLine("{0}-{1}-{2}", item.Element("ProductID").Value, item.Element("ProductName").Value, item.Element("UnitPrice").Value);
    });

    3、查询子孙节点

    Descendants轴方法与Elements类型相似,不过Elements只查找当前元素下的直接子节点,而Descendants则会遍历当前元素下任意层级的子元素。

    var query = from b in root.Descendants("Book")
                select b;
    foreach (var item in query)
    {
        Console.WriteLine(item.Element("ProductName").Value);
    }

    4、查询属性

    var query = from p in xml.Nodes().OfType<XElement>()
                where (int)p.Attribute("ID").Value == 1
                select new
                {
                    ID = p.Attribute("ID").Value,
                    ProductID = p.Element("ProductID").Value,
                    ProductName = p.Element("ProductName").Value
                };

    5、查询出来填充到List:

    XElement root = XElement.Load(@"like.xml");
    var query =
                from ele in root.Elements("book")
                select new { author = ele.Element("author").Value, 
                            price = ele.Element("price").Value
                           };
    
    String xml = null;
    foreach (var item in query)
    {
        xml = xml + item.ToString() + "
     -------  
    ";
    }

    六、操作节点

    1、增加节点

    1. Add():    在 XContainer 的子内容的末尾添加内容。
    2. AddFirst(): 在 XContainer 的子内容的开头添加内容。
    3. AddAfterSelf():  在 XNode 后面添加内容。
    4. AddBeforeSelf() :  在 XNode 前面添加内容。
    XElement product = new XElement
    (
        "Product",
        new XAttribute("ID", 2),
        new XElement("ProductName", "LINQ to Object"),
        new XElement("UnitPrice", 20m),
        new XElement("Remark", "")
    );
    
    el.Add(product);

    2、修改、替换节点

    • SetAttributeValue(): 设置属性的值。 如果该属性不存在,则创建该属性。 如果值设置为 null,则移除该属性。
    • SetElementValue():  设置子元素的值。 如果该元素不存在,则创建该元素。 如果值设置为 null,则移除该元素。
    • Value:用指定的文本替换元素的内容(子节点)。
    • SetValue():  设置元素的值。
    • ReplaceAll ():   替换元素的所有内容(子节点和属性)。
    • ReplaceAttributes():   替换元素的属性。
    • ReplaceWith():   用新内容替换节点。
    • ReplaceNodes():   用新内容替换子节点。
    IEnumerable<XElement> products = from e in el.Elements("Product")
                                        where e.Attribute("ID").Value == "1"
                                        select e;
    if (products.Count() > 0)
    {
        XElement product = products.First();
        product.SetAttributeValue("ID", 3);
        product.ReplaceNodes
        (
            new XElement("ProductName", "LINQ to XML Version 2"),
            new XElement("UnitPrice", 30)
        );
    }

    3、删除节点

    • RemoveAll():  移除元素的所有内容(子节点和属性)。
    • RemoveAttributes():  移除元素的属性。
    • ReplaceNodes():  删除子节点。
    • Remove():  移除掉整个节点或节点集合
    IEnumerable<XElement> products = from e in el.Elements("Product")
                                        where e.Attribute("ID").Value == "2"
                                        select e;
    if (products.Count() > 0)
    {
        products.First().Remove();
    }
    
    xml.Element("Product").Remove(); // 删除第一个Product子元素
    xml.Elements("Product").Remove(); // 删除全部Product子元素
    
    xml.SetElementValue("Product", null); // 删除第一个Product子元素
    
    xml.Element("Product").SetElementValue("ProductID", 1); // 修改ProductID子元素
    xml.Element("Product").SetElementValue("ProductID", null); // 删除ProductID子元素

    4、属性操作

    //添加属性: 
    product.Add(new XAttribute("ID", 1));
    
    //修改属性:
    product.SetAttributeValue("ID", 2);
    
    //删除属性:
    product.Attribute("ID").Remove();

    六、使用XPath查询

    为了在LINQ XML中使用XPath查询,需要添加System.Xml.XPath命名空间。如下:

    using Sytem.Xml.XPath;

    添加了System.Xml.XPath命名空间,XNode类就添加了一系列扩展方法。有了这些扩展方法,我们可以有两种选择处理XML。使我们的应用程序可以进行一个平稳的移植。

    1. CreateNavigator方法,这允许我们从一个现有的XNode对象创建一个XPathNavigator对象。
    2. XPathEvaluate方法允许对XNode上的XPath表达式进行计算。
    3. XPathSelectElement方法返回第一个匹配表达式的元素, XPathSelectElements方法返回所有匹配表达式的元素。

    为了查询如下XML数据:

    <category name="Technical">
        <category name=".NET">
            <books>
                <book>CLR via C#</book>
                <book>Essential .NET</book>
             </books>
        </category>
         <category name="Design">
            <books>
                 <book>Refactoring</book>
                <book>Domain Driven Design</book>
                <book>Patterns of Enterprise Application Architecture</book>
             </books>
         </category>
         <books>
             <book>Extreme Programming Explained</book>
             <book>Pragmatic Unit Testing with C#</book>
             <book>Head First Design Patterns</book>
         </books>
     </category>

    如何使用XPath查询XML数据:

    XElement root = XElement.Load("categorizedBooks.xml");
    var books = from book in root.XPathSelectElements("//book")
                select book;
    
    foreach (XElement book in books)
    {
        Console.WriteLine((string)book);
    }

    七、XML进行转换

    1、使用XSLT进行转换

    string xsl = @"<?xml version='1.0' encoding='UTF-8' ?>
    <xsl:stylesheet version='1.0'  xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>     <xsl:template match='books'>         <html>             <title>Book Catalog</title>             <ul>                 <xsl:apply-templates select='book'/>
                </ul>
            </html>     </xsl:template>     <xsl:template match='book'>         <li>
                <xsl:value-of select='title'/> by <xsl:apply-templates select='author'/>         </li>     </xsl:template>     <xsl:template match='author'>         <xsl:if test='position() > 1'>, </xsl:if>         <xsl:value-of select='.'/>     </xsl:template> </xsl:stylesheet>
    ";
    
    XElement books = XElement.Load("books.xml");
    XDocument output = new XDocument();
    using (XmlWriter writer = output.CreateWriter())
    {
        XslCompiledTransform xslTransformer = new XslCompiledTransform();
        xslTransformer.Load(XmlReader.Create(new StringReader(xsl)));
        xslTransformer.Transform(books.CreateReader(), writer);
    }
    Console.WriteLine(output);

    为了重用转换代码,可以将转换逻辑封装到一个扩展方法中

    public static class XmlExtensions
    {
        public static XDocument XslTransform(this XNode node, string xsl)
        {
            XDocument output = new XDocument();
            using (XmlWriter writer = output.CreateWriter())
            {
                XslCompiledTransform xslTransformer = new XslCompiledTransform();
                xslTransformer.Load(XmlReader.Create(new StringReader(xsl)));
                xslTransformer.Transform(node.CreateReader(), writer);
            }
            return output;
        }
    }
    
    //使用这个扩展方法
    XElement.Load("books.xml").XslTransform(xsl));

    2、使用 LINQ to XML 转换 XML

           XSL 并不是改变 XML 格式的唯一方式(过去它是唯一实际可行的办法),但今天,LINQ to XML 提供了一个富有竞争力的选择。要使用 LINQ to XML 进行转换,你需要一个运用投影的 LINQ 表达式。技巧在于投影必须返回一个 XElement 而不是匿名类型。

    string xmlFile = Server.MapPath("DvdList.xml");
    XDocument doc = XDocument.Load(xmlFile);
     
    XDocument newDoc = new XDocument(
        new XDeclaration("1.0", "utf-8", "yes"),
        new XElement("Movies",
            from DVD in doc.Descendants("DVD")
            where (int)DVD.Attribute("ID") < 3
            select new XElement[]
            {
                new XElement ("Moive",
                    new XAttribute("name", (string)DVD.Element("Title")),
                    DVD.Descendants("Star")
                )
            }
        )
    );
     
    string newFile = Server.MapPath("MovieList.xml");
    newDoc.Save(newFile);

    结果:

    <?xml version="1.0" encoding="utf-8" standalone="yes"?>
    <Movies>
      <Moive name="The Matrix">
        <Star>Keanu Reeves</Star>
        <Star>Laurence Fishburne</Star>
      </Moive>
      <Moive name="Forrest Gump">
        <Star>Tom Hanks</Star>
        <Star>Robin Wright</Star>
      </Moive>
    </Movies>

    基于 LINQ 转换的语法通常要比使用 XSL 样式表的转换更容易理解,并且更加精确你也可以很方便的替换为另一个 IEnumable<T>的集合,包括 LINQ to Entities 获得的结果集,然后随意打包成另一种格式的 XML 文档。

  • 相关阅读:
    微信开发生成带参数的二维码的讲解
    C#利用最新版的WPS实现导入导出
    【模版消息】C#推送微信模版消息(Senparc.Weixin.MP.dll)
    Photoshop的辅助线
    Newtonsoft.Json 两个Attribute含义
    VUE2.0 饿了吗视频学习笔记(二):新版本添加路由和显示Header
    VUE2.0 饿了吗视频学习笔记(一):VUE示例data.json
    Windows句柄数限制
    The CLI moved into a separate package: webpack-cli.解决办法
    Winform窗体设计工具源码
  • 原文地址:https://www.cnblogs.com/springsnow/p/9428755.html
Copyright © 2011-2022 走看看