XML LINQ简介

本章包括

n   XML LINQ 设计原则

n   XML LINQ 类层次

n   加载、解析和操作 XML

XML LINQ 允许我们使用我们已经熟悉的 LINQ 查询语法查询 XML 数据,而不是学习查询 XML 的新的 API 。此外, XML LINQ 也提供了一些轻量级 XML API 用来操作 XML ,这些 API 利用了提供了类似 DOM 的操作,但是在设计上更加直观。本章的目的就是学习 XML LINQ 提供的 API 。为了成为 XML LINQ 的专家,我们首先需要掌握一些关键的设计原则,在本章中,我们将会介绍这些设计原则和 LINQ XML API 的核心概念。

9 . 1 什么是 XML API

XML API 提供了操作 XML 数据的编程接口。通过使用这些 API ,我们可以创建使用 XML 的程序,如创建一个使用列表 9.1 所示 XML 的应用程序,列表 9.1 包含了一个站点地址列表。

列表 9.1  包含站点链接的 XML 文件

<links>

<link>

<url>http://linqinaction.net</url>

<name>LINQ in Action</name>

</link>

<link>

<url>http://hookedonlinq.com</url>

<name>Hooked on LINQ</name>

</link>

<link>

<url>http://msdn.microsoft.com/data/linq/</url>

<name>The LINQ Project</name>

</link>

</links>

我们可以打开一个 XML 文件读取其内容,还可以修改指定元素的内容,这些工作就是 XML API 工作的基本内容。在 .NET 中,我们有大量的 API 用来完成这些操作。如: XmlTextReader XmlReader XmlNode XPathNavigator 等。每种 API 都有自己的优点和缺点。但是都能完成开发者处理 XML 的目标。既然已经有那么多可用的 XML API 可用,又为什么需要 XML LINQ 呢?

9. 2 为什么我们需要 XML LINQ

使用那些现有的 API ,开发者需要做很多的思考。我需要知道 XSLT, XPath, XQuery, XML DOM 等技术内容,而这些技术跟 C #是一个完全不同的概念模型。如果每天都在使用这些 API 处理 XML ,这可能不是一个问题。但是对于大多数开发者而言,针对这些 XML 技术的工作量是巨大的。

XML LINQ 的目标就是提供一种简单处理 XML 的方法。它提供了查询和转换 XML 的能力,并将 XQuery XPath 集成到 .NET 编程语言中。除了提供给开发者更易于使用的 XML API XML LINQ 同样利用了编程语言的优点,如利用扩展方法,匿名类型和 lambda 表达式等。下面就让我们看一下 XML LINQ 的设计原则。

9. 3 XML LINQ 设计原则

为了让 XML 开发人员的工作更加高效和愉快,微软使用了一种全新的方法设计了 XML LINQ 。无论从概念上还是性能上, XML LINQ 都是一个轻量级的 XML API 。下面会使用 XML LINQ 创建一个 XML 文档,用以阐述 XML LINQ 如何让我们的工作变得高效。我们的目标是创建一个包含 book 信息的 XML 文档,如列表 9.2

列表 9.2    包含 Book 信息的 XML 文档

 

<books>

<book>

<title>LINQ in Action</title>

<author>Fabrice Marguerie </author>

<author>Steve Eichert</author>

<author>Jim Wooley</author>

<publisher>Manning</publisher>

</book>

</books>

下面是使用传统的 XML API 创建文档的代码,如列表 9.3

列表 9.3    使用 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");

author2.InnerText = "Steve Eichert";

XmlElement author3 = doc.CreateElement("author");

author3.InnerText = "Jim Wooley";

XmlElement title = doc.CreateElement("title");

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

 

这种传统的编程方式很难让我们看到创建的目标 XML 是什么样子。此外还需要创建很多临时变量用来保持那些我们创建的元素。结果是这种代码很难阅读,调试和维护。下面让我们看看 XML LINQ 如何创建 XML 文档,如列表 9.4:

列表 9.4    使用 XML LINQ 创建 XML 文档

new XElement("books",

new XElement("book",

new XElement("author", "Fabrice Marguerie"),

new XElement("author", "Steve Eichert"),

new XElement("author", "Jim Wooley"),

new XElement("title", "LINQ in Action"),

new XElement("publisher", "Manning")

)

);

通过使用这些便利的构造函数,我们可以使用 XML LINQ 快速的编写创建我们文档的代码。不用担心创建那些父节点元素了,而且代码结构与结果 XML 文档的结构非常相似。这就是设计 XML LINQ 的关键概念。

9 . 3 . 1    关键概念:功能构建

XML LINQ 为创建 XML 元素提供了一种更强大的方式:功能构建模式。功能构建模式允许使用一个语句创建一个 XML 树。这使得创建过程与结果很相似。这是传统的 API 所不具备的。功能构建模式的目的是让我们的头脑中想着 XML 而不是创建 XML 的技术。图 9.1 显示 XML LINQ 代码何其创建的 XML 文本,它们非常相似。

 

9.1    XML LINQ 代码和其创建的 XML 文本结果

下面要讲述的是 XML LINQ 的另一个关键概念,自由上下文( context-free XML 创建。

9 . 3 . 2    关键概念:自由上下文 XML 创建

当使用 DOM 创建 XML 的时候,每个对象都必须在其文档对象的上下文中创建。使用 XML LINQ ,元素和属性可以在文档对象之外创建。这允许程序员用更自然的方法创建元素,而不是使用那些工厂方法。这么做的结果使得代码更容易阅读和理解,此外,创建元素和属性变得更加容易,因为不再需要一个文档节点。虽然文档节点失去了以往的高贵地位,但是在创建那些包含 XML 声明,文档类型定义和 XML 处理指令的时候, XML LINQ 同样提供了 XDocument 类。下面要讲述的是另一个关键概念。

9.3. 3     关键概念:简单名称

XML 中最令人困惑的一个方面就是 XML 名称, XML 命名空间和命名空间前缀。当使用 DOM 创建元素的时候,开发人员有很多重载的工厂方法允许指定元素名称的细节。 DOM 计算元素名称的方式会让人感到困惑。使用 XML LINQ 的时候, XML 名称大大的简化了。不用再担心本地名称,限定名称,命名空间和命名空间前缀,我们可以只关注一个完整的扩展名称。 XName 类表示一个完整的扩展名称,它包含了元素的名称空间和本地名称。当一个 XName 包含命名空间的时候,会按如下形式组织: {http://schemas.xyxcorp.com/}localname

除了简化命名, XML LINQ 同样使得针对指定了命名空间的 XML 查询变得简单。如下查询 RSS 反馈的查询代码。列表 9.5 显示了 XML 文档结构:

列表 9.5    使用 XML 命名空间的 RSS 反馈

<?xml-stylesheet href=http://iqueryable.com/friendly-rss.xsl type="text/xsl" media="screen"?>

<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/"

xmlns:slash="http://purl.org/rss/1.0/modules/slash/"

xmlns:wfw="http://wellformedweb.org/CommentAPI/">

<channel>

<title>Steve Eichert</title>

<link>http://iqueryable.com/</link>

<generator>ActiveType CMS v0.1</generator>

<dc:language>en-US</dc:language>

<description />

<item>

<dc:creator>Steve Eichert</dc:creator>

<title>Parsing WordML using LINQ to XML</title>

<link>http://iqueryable.com/LINQ/ParsingWordMLusingLINQ to XML</link>

<pubDate>Wed, 02 Aug 2006 15:52:44 GMT</pubDate>

<guid>http://iqueryable.com/LINQ/ParsingWordMLusingLINQ to XML</guid>

<comments>

http://iqueryable.com/LINQ/ParsingWordMLusingLINQ to XML#comments

</comments>

<wfw:commentRss>

http://iqueryable.com/LINQ/ParsingWordMLusingLINQ to

XML/commentRss.aspx

</wfw:commentRss>

<slash:comments>1</slash:comments>

<description>Foo…</description>

</item>

</channel>

</rss>

RSS 文档使用了一些 XML 命名空间: http://purl.org/dc/ele-ments/1.1/ , http://purl.org/rss/1.09/modules/slash/ http://well-formedweb.org/commentapi/ 。列表 9.6 显示了查询使用了上述命名空间的元素的 DOM 代码。

列表 9.6    通过 DOM 查询包含命名空间的元素

XmlDocument doc = new XmlDocument();

doc.Load("http://iqueryable.com/rss.aspx");

 

XmlNamespaceManager ns = new XmlNamespaceManager(doc.NameTable);

ns.AddNamespace("dc", "http://purl.org/dc/elements/1.1/");

ns.AddNamespace("slash", "http://purl.org/rss/1.0/modules/slash/");

ns.AddNamespace("wfw", "http://wellformedweb.org/CommentAPI/");

 

XmlNodeList commentNodes = doc.SelectNodes("//slash:comments", ns);

foreach(XmlNode node in commentNodes)

{

Console.WriteLine(node.InnerText);

}

我们创建一个 XMLNamespaceManager 对象,用来查询那些使用特定命名空间的元素,如果需要查询那些没有命名空间的元素,可以使用如下代码:

XmlNodeList titleNodes = doc.SelectNodes("/rss/channel/item/title");

foreach(XmlNode node in titleNodes)

{

Console.WriteLine(node.InnerText);

}

 

XML LINQ 提供了一个更自然的处理命名空间的方法。忘了 XMLNamespaceManager 吧,但需要记住如下一个简单规则:

处理元素和属性的时候,总是使用完整扩展名

列表 9.7 显示了 XML LINQ 查询 XML 的代码

列表 9.7    使用 XML LINQ 查询包含命名空间的元素

 

XElement rss = XElement.Load("http://iqueryable.com/rss.aspx");

XNamespace dc = "http://purl.org/dc/elements/1.1/";

XNamespace slash = "http://purl.org/rss/1.0/modules/slash/";

XNamespace wfw = "http://wellformedweb.org/CommentAPI/";

 

IEnumerable<XElement> comments = rss.Descendants(slash + "comments");

foreach(XElement comment in comments)

{

Console.WriteLine((int)comment);

}

 

IEnumerable<XElement> titles = rss.Descendants("title");

foreach(XElement title in titles)

{

Console.WriteLine((string)title);

}

如上所示, XML LINQ 处理命名空间的方式是很直接的。在我们的第一个查询中,我们将本地名称追加到一个 XNamespace (slash) 上。在第二个查询中,我只是使用本地名称进行查询。通过将本地名称和命名空间合并一个概念中, XML LINQ 使得处理 XML 名称,命名空间,命名空间前缀时变得简单。所有有关名称的概念都被封装到一个 XName 中。

下面将会讲出 XML LINQ 的类层次,通过这些类,我们可以轻松的构建一个 XML 应用程序。

9. 4 XML LINQ 类层次

在使用 XML LINQ 处理 XML 之前,首先需要理解 XML LINQ 提供的那些主要的类。幸运的是, XML LINQ 有一个相对较小的层次结构,如图 9.2 所示:

 

 

9.2    XML LINQ 类层次结构

在图 9.2 的上方是 XObject 类, XObject 类是 XML LINQ 中大多数类的基类。它提供了一个 AddAnnotation 方法来添加用户定义信息,如行号,到 XML LINQ 对象中,也提供了一个 RemoveAnnotation 方法来删除注释。为了获取注释, XObject 对象提供了 Annotation, Annotation<T>, Annotations Annotations<T> 这几个辅助方法。

XObject 类的下方是抽象的 XNode 类, XNode 类是 XML LINQ 中表示元素节点的类的基类。它提供了许多更新和获取内容的方法,如 AddAfterSelf, AddBeforeSelf, Remove Ancestors, ElementsAfterSelf, ElementsBeforeSelf, NodesAfterSelf, and NodesBeforeSelf

XNode 类的下方是 XContainer 类。 XContainer 是可以包含其它 XNode 对象的类的基类。 XContainer 添加了额外的更新方法,如 Add, AddFirst, RemoveNodes ReplaceNodes 。还添加了一些辅助方法,如 Nodes, Descendants, Element Elements XContainer XML LINQ 中最重要的两个类的基类: XElement XDocument XElement 类表示一个 XML 元素节点,它可以包含其它元素节点。它添加了其它的辅助方法,如 Attributes, AncestorsAndSelf DescendantAndSelf, 及一些更新方法 RemoveAll, RemoveAttributes, SetElementValue SetAttributeValue 。作为 XML LINQ 中最重要的类, XElement 同样提供了一个静态的 Load 方法,它允许从外部源加载 XML 。还提供了一个 Parse 方法,允许从一个 XML 字符串创建一个 XElement 对象。最后 XElement 提供了一个 Save 方法,用来将内存中的 XML 内容存储到磁盘中。同样, WriteTo 方法允许将 XML 写入到一个 XmlWriter 中。

XAttribute 类表示 XML LINQ 中的元素属性。跟其它的类不同, XAttribute 类并不从 XNode 继承。 XAttribute

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值