LINQ实战阅读笔记---第九章 LINQ to XML 入门

LINQ to XML 设计原则:为了让大多数开发人员能够更加简单有效地操作XML,微软在LINQto XML 中设计了一种全新的方式。无论是从概念的角度考虑,还是从内存占用以及性能方面分析,LINQ to XML都是一种轻量级的XML编程API。

       为了能够清楚的表述出LINQ to XML的设计原则,我们先来使用当前最为流行的XML编程API—DOM  来创建一个简单的XML文档,然后再用LINQ to XML 创建同样的XML文档,并对这两种做法的实现方式进行比较。

       我们的目标是创建出一个XML文档,其中将要包含LINQBooks实例程序中图书的详细信息。

<books>
       <book>
              <title>LINQ inAction</title>
              <author>FabriceMarguerie</author>
              <author>Steve Eichert</author>
              <author>JimWooley</author>
              <publisher></publisher>
       </book>
</books>

使用DOM生成XML文档

XmlDocument doc =new XmlDocument();
XmlElement books =doc.CreateElement("books");
XmlElement author1 =doc.CreateElement("author");
author1.InnerText ="Fabrice Marguerie";
XmlElement author2 =doc.CreateElement("author");
ahthor2.InnerText ="Steve Eichert";
XmlElement author3 =doc.CreateElement("author");
author3.InnerText="Jim Wooley";
XmlElement title =doc.CreateElement("author");
title.InnerText ="LINQ in Action";
XmlElement book =doc.CreateElement("book");
book.AppendChild(author1);
book.AppendChild(author2);
book.AppendChild(author3);
book.AppendChild(title);
books.AppendChild(book);
doc.AppendChild(books);

使用LINQ toXML 生成XML 文档

new XElement("books",
       new XElement("book",
              newXElement("author","Fabrice Marguerie"),
              newXElement("author","Steve Eichert"),
              newXElement("author","Jim Wooley"),
              newXElement("title","LINQ in Action"),
              newXElement("publisher","Manning")
       )
);

加载XML

       LINQ to XML 允许我们从多种不同的输入中加载XML,包括文件、URL和XmlReader等。若想加载某个XML文件,那么可以使用Xelement类的Load方法,如下方法将某个XML文件加载至一个Xelement中:

Load方法也可以从某个网站中加载XML。如下:

XElement x = XElement.Load(@”http://msdn.microsoft.com/rss.xml”);
默认情况下,在XML被加载至Xdocument或Xelement中以后,文档中的空格将被移除。若你希望保留原文档中的空格,可以使用Load方法的一个重载。该重载接受一个LoadOptions标记,用来给出加载XML时的选项。这些选项包括Node、PreserveWhitespace、SetBaseUri和SetLineInfo。下面这段代码在从MSDN加载RSS时使用LoadOptions.PreserveWhitespace保留了其中的空格:
string xmlUrl = "http://msdn.microsoft.com/rss.xml";
XElement x = XElement.Load(xmlUrl,LoadOptions.PreserveWhitespace);
下面的代码首先使用XmlReader的Create静态方法加载了名为books.xml的文件。随后在XmlReader中遍历其每一个节点,直到找到一个NodeType为XmlNodeType.Element的节点为止。当XmlReader位于某个元素节点上之后,即可调用Xelement的ReadFrom静态方法并传入该XmlReader,这样即可创建出一个Xelement的实例。
using (XmlReaderreader = XmlReader.Create("books.xml"))
            {
                while(reader.Read())
                {
                    if(reader.NodeType == XmlNodeType.Element)
                    {
                        break;
                    }
                }
                XElementbooksXml = (XElement)XNode.ReadFrom(reader);
            }
若想用XmlReader中包含的某一段XML创建Xelement对象,那么则需要首先使用XmlReader的API找到合适的节点,然后再将该XmlReader传递给Xelement的ReadFrom方法。例如,若想加载books.xml文件中的第一个book元素,可以用如下代码:
using (XmlReaderreader = XmlTextReader.Create("books.xml"))
            {
                while(reader.Read())
                {
                    if(reader.NodeType==XmlNodeType.Element&&reader.Name=="book")
                        break;
                }
                XElementbooksXml = (XElement)XNode.ReadFrom(reader);
            }
至此,我们只介绍了将XML加载至Xelement对象中的做法。若你希望同时也能够加载XML声明(XDeclaration)、XML处理指令(XProcessingInstruction)、XML文档类型定义(XDocumentType)或XML注释(XComment)等内容,那么则应将XML文档加载至Xdocument对象,而不是Xelement对象中。将XML加载至Xdocument对象中的方法和加载至Xelement的方法非常类似。Xdocument类的Load静态方法和Xelement的Load方法有着同样的重载,二者行为上也完全一致。唯一的区别在于Xdocument能够包含其他类型的子节点。例如,若我们在加载MSDN的RSS时同时希望能够访问到文件中的每一个子节点(包括XML声明、DTD、处理指令以及注释等),那么即可将该RSS加载至Xdocument对象中:
XDocument msdnDoc = XDocument.Load("http://msdn.microsoft.com/rss.xml");
创建XML
LINQ to XML 提供了一种非常强大的创建XML元素的方法---函数式创建。这种方法允许开发者在一条语句中创建出一颗完整的XML树。如下所示的XML用LINQ to XML进行创建
XElement xml = new XElement("books",
                  newXElement("book",
                      newXElement("title","LINQ in Action"),
                      newXElement("author","Fabrice Marguerie"))
               );
使用LINQ toXML 中提供的命令式的代码结构来创建XML
XElement book = new XElement("book");
book.Add(new XElement("title", "LINQin Action"));
book.Add(new XElement("author", "FabriceMarguerie"));
 
XElement books = new XElement("books");
books.Add(book);
       在创建XML时,我们一般都需要在其中使用某些命名空间以及命名空间前缀。若想在创建元素时同时提供命名空间信息,我们既可以在Xelement狗仔函数的第一个参数中给出完全展开的XML名称。
通过完全展开的Xname创建XElement
XElement book = new XElement("{http://linqinaction.net}book");
通过Xnamespace和局部名称创建XElement
XNamespace ns = "http://linqinaction.net";
XElement book = new XElement(ns+"book");
       若只是某一个元素需要命名空间,那么一般情况下可以直接给出该元素的完全展开名称,而没有必要额外创建Xnamespace对象。不过若是几个元素均使用了同一个命名空间,那么先定义一个Xnamespace,以后再需要多次使用它时则能够让代码变得更加清晰。
创建XML文档
       在使用Xdocument对象时,你会发现其很多功能都似曾相识。以前提到过的所有应用于元素上的方法,都能够应用到Xdocument上。二者之间的不同之处在于其允许添加的子节点类型。对于Xelement来说,其子节点可以是Xelement对象、Xattribute对象、Xtext、Ienumerable以及字符串。而Xdocument则允许添加如下类型的子节点:
       一个XdocumentType对象,用来表示DTD;
       一个Xdeclaration对象,用来表示XML声明中的相关信息,包括XML版本、文档的字符编码以及该XML文档是否为独立等;
       任意数量的XprocessingInstruction对象,用来提供某些处理XML时将用到的信息;
       一个Xelement对象,作为该XML文档的根节点;
       任意数量的Xcomment对象。这些注释将成为根节点的兄弟节点,不过Xcomment对象不能作为参数列表中的第一个,因为以注释开头的XML文档是不合法的。
使用Xdocument类型以及函数式创建模式生成XML文档
XDocument doc = newXDocument(
       newXDeclaration("1.0","utf-8","yes"),
       newXProcessingInstruction("XML-stylesheet","friendly-rss.xsl"),
       new XElement("rss",
       new XElement("channel","mychannel")
       )
);
向XML中添加内容
       LINQ to XML 为操作现有的XML文件提供了非常强大的支持,如果要在建好的XML中插入新元素或属性,这时即可使用其Add方法。Add方法的签名和Xelement的签名非常类似---他同样提供了两个重载。第一个重载只接受单一的对象,第二个则允许同时插入一系列的对象。
public voidAdd(object content)
public voidAdd(params object[] content)
上述Add方法的两个重载允许我们继续使用熟悉的函数式创建模式。若想将某个元素添加为现有Xelement的子节点,那么可以使用如下代码:
XElement book = newXElement("book");
book.Add(newXElement("author","Dr. Seuss"));
当然,任何能够作为Xelement子节点的类型都可以传给上述content参数。例如,若想为当前Xelement添加一个属性,我们可以将一个Xattribute对象传入至Add方法中。
XElement book = newXElement("book");
book.Add(newXAttribute("publicactioniDate","October 2005"));
使用Add方法为Xelement添加内容
XElement books = newXElement("books");
books.Add(newXElement("book",
              newXAttribute("publicactionDate","May 2006"),
              newXElement("author","Chris Sells"),
              newXElement("title","Windows Forms Programming")
       )
);
     另外需要注意的是,Add方法能够自动处理传入的Ienumerable对象。若Add方法检测到其参数实现了Ienumerable,那么该Ienumerable中的每一个元素都将被依次加入到当前Xelement中。这个特性使得在构造XML时可以使用LINQ查询,因为标准查询操作符以及LINQ to XML提供的所有XML查询方法均能够返回Ienumerable<XElement>。下面这段代码巧妙的借助了Add方法支持Ienumerable的特性,将现有XML文档中的所有元素添加到了另一个Xelement中。
XElementexistingBooks = XElement.Load("ss.xml");
XElement books = newXElement("books");
books.Add(existingBooks.Elements("book"));
默认情况下,在为Xelement添加新元素时,该元素会被添加至最后的位置。若插入的内容是Xelement,那么该元素将作为Xelement的最后一个子节点。若插入的内容是Xattribute,那么该元素将作为Xelement的最后一个属性。若这样的实现无法满足你的实际要求,你还可以使用Xelement提供的其他添加方法。例如,若想将元素添加在最开始的位置,即添加为Xelement的第一个子节点,那么可以调用AddFrist方法。若需要更加精确的指定元素插入的位置,则可以首先导航至要插入的位置,然后调用AddAfterSelf或AddBeforeSelf。例如,若希望将一个book元素添加为books这个Xelement的第二个子节点,那么可以使用如下代码:
XElement newBook =new XElement("book","LINQ in Action");
XElement firstBook =books.Element("book");
firstBook.AddAfterSelf(newBook);
从XML中移除内容
Xelement提供了几种用来移除其中子元素的方法。其中最直接的一种就是首先找到该元素,然后调用其Remove方法。Remove方法能够用于单一元素上,也能够用于Ienumerable之上。在Ienumerable上调用Remove方法能够一次性地移除其中包含的所有元素。如下代码演示了移除一个book元素以及所有book元素的方法。
books.Element("book").Remove();
books.Elements("book").Remove();
另外一种不那么直观的移除元素的做法就是调用Xelement的SetElementValue方法---传入null作为其参数。
Books.SetElementValue(“book”,null);
若仅仅希望移除元素中的内容,但依然保留元素的标签,那么可以使用元素的Vlaue属性。我们可以先找到该元素,然后设置其Value属性为空字符串:
books.Element("book").Element("author").Value= String.Empty;
更新XML的内容
SetElementValue方法,更新某个节点的内容
XElement books = newXElement("books.xml");
book.Element("book").SetElementValue("author","BillGates");
需要注意的是,SetElementValue只能支持简单的内容。若传入的不是字符串,那么SetElementValue将会尝试使用Xcontainer的GetStringValue方法将其转换为字符串。如下:将author元素的值设置为一个Xelement:
books.Element("book").SetElementValue("author",newXElement("foo"));
那么Xcontainer将抛出异常,因为其不支持将Xobject及其派生类作为内容。
若想处理更加复杂的内容,那么则应该使用定义于Xcontainer中的ReplaceNodes方法。
ReplaceNodes支持传入各种类型的内容,并支持多个参数。因此,修改上述代码中的SetElementValue为ReplaceNodes:
books.Element("book").Element("author").ReplaceNodes(newXElement("foo"));
Xelement的ReplaceNodes方法能够移除该元素中的所有子元素,然后用传入的参数作为其新的内容。Content参数可以是任何能够作为Xelement的子元素的对象,包括Ienumerable(其中的每个元素将被一次添加)。ReplaceNodes还提供了一个重载,能够接受多个参数,允许用这些参数一次性地替换掉元素的原有内容。如下:
books.Element("book").ReplaceNodes(
       new XElement("title","Ajaxin Action"),
       newXElement("author","Dave Crane")
);
操作属性
XAttribute类用在LINQ to XML 中表示XML中的属性。与前面介绍的其他XML API不同的是,属性和元素/节点分别来自于不同的继承体系。在LINQto XML中,属性仅仅是简单的名称/值对。因此,Xattribute对象的构造函数也相应地接受了name和value作为参数。
       在创建XML时,我们可以将属性以参数的形式传递给函数式创建语句或Add方法中。例如,若想在book元素中添加一个出版日期属性,那么可以在创建时使用如下语句:
newXElement("book",new XAttribute("pubDate","July31,2006"))
或者在创建完成之后调用Add方法,将属性传递给该方法的content参数:
book.Add(newXAttribute("pubDate","July 31,2006"));
除了使用Add方法之外,我们也可以使用元素的SetAttributeValue方法设置其属性。SetAttributeValue方法类似于前面介绍的SetElementValue,用来为现有的Xelement添加或更改属性。若Xelement中已经存在了该属性,那么其值将被更新,若没有存在,那么将会添加。例如,若想更改pubDate属性的值,可以按照如下代码调用SetAttributeValue方法:
book.SetAttributeValue("pubDate","October1,2006");
与SetElementValue类似的是,若传入null,那么SetAttributeValue能够移除元素的某一属性。此外,Xattribute还提供了一个Remove方法,专门用来移除某一属性。
Book.Attribute(“pubDate”).Remove();
保存XML
保存XML的方法非常直观。Xelement和Xdocument类均提供了Save方法,能够将XML保存到文件、XmlTextWriter或XmlWriter中。若想将Xelement存放于磁盘中,我们可以调用Save方法,并传入该XML文件的路径。如:book.Save(@”c:\books.xml”);
 
小结
       建立在LINQ之上的LINQ to XML允许我们使用标准查询操作符对XML文件进行查询。LINQ toXML提供呃若干易于使用且功能强大的查询XML元素的方法。与LINQ to XML 强大查询功能媲美的是其API的简洁性,这也级大地提高了开发人员的编程体验。
       LINQ to XML 是一个专门为LINQ设计的轻量级XMLAPI,它构造于LINQ所带来的语言方面创新之上,并引入了一些全新的概念,包括函数式创建、上下文无关的XML创建以及对XML命令的简化等。虽然微软公司完全可以通过对原有XML API进行改进来支持LINQ,不过LINQ to XML 这个全新的呃设计却让该API彻底挣脱了原有框架的枷锁,极大地方便 了LINQ中对XML的操作过程。
       LINQ to XML中核心类是Xelement。除此之外,LINQto XML还提供了Xattribute、Xdocument和Xname等重要类。通过将上述这些核心类与编程API配合使用,LINQto XML提供了一整套及其直观的加载、解析、创建、更新以及保存XML的方法。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值