XPath 和 XQuery 在某些方面很相似。XPath 还是 XQuery 完整不可分割的一部分。这两种语言都能够从 XML 文档或者 XML 文档存储库中选择数据。本文简要介绍了 XPath 和 XQuery,以及如何使用 XQuery 对 XPath 的扩展。

虽然 XPath 和 XQuery 都能实现一些相同的功能,但是 XPath 比较简洁而 XQuery 更加强大和灵活。对于很多查询来说 XPath 非常合适。比如,从 XML 文档中的部分记录建立电话号码的无序列表,使用 XPath 实现最简单。但是如果需要表达更复杂的记录选择条件的表达式、转换结果集或者进行递归查询,则需要使用 XQuery。

XPath

XPath 是一种领域专用语言(Domain-Specific Language, DSL),并很快成为了其他更通用语言的重要组成部分。编程语言通过模块和类把 XPath 结合进来,有时候甚至直接进入语言的语法。这种情况和以前正则表达式的情况类似。

由于从 XML 文档中提取特定的数据时,XPath 能够为开发人员节省大量的时间和精力,XPath 得以流行起来。即使从未接触过 XPath 的人也能很快利用其强大的功能。比如清单 1 中的 XML 片段。

清单 1. XML 文档
   <users>
<user>
<name>
<first>Lola</first>
<last>Solis</last> </name>
<age>2</age>
</user>
<user>
<name> <first>Nina</first>
<last>Serafina</last>
</name>
<age>4</age> <visits>
<first>2008-01-15</first>
<last>2008-02-15</last>
</visits>
</user> <user>
<name>
<first>Tracy</first>
<last>Keller</last>
</name> <age>35</age>
</user>
</users>

如果需要获得文档中青少年的姓氏列表,可使用下面的 XPath 表达式。

清单 2. 选择 18 岁以下用户的姓氏
  /user[age lt 18]/name/last/text()

 (: Result
Solis
Serafina
:)

设想一下如果不使用 XPath,提取同样的数据您得编写多少代码。即便有正则表达式的帮助,如何排除所访问节点最后一个标记中的值也需要动点脑筋。

上面的 XPath 表达式不但准确而且非常清晰易懂。即便是对于不懂 XPath 的人,快速地扫一眼也能明白这个表达式的作用。XPath 之所以有效是因为它非常强大,而且有很长的发展历史。无论结构多么复杂,这种语言都能够理解 XML 文档中的节点,而且更重要的是,能理解这些节点之间的关系。因此可以编写精确的表达式来表示元素和元素值,以及属性、处理指令等等。

许多 XML 查询很难用比 XPath 更清晰、更准确的方式来表达。但是 XPath 固有的 DSL 特性及其设计的目标,却为程序员带来了很大的局限性。下面一节简要介绍了 XQuery 语言,并举出了 XPath 无法单独解决的问题。这些问题要求程序员越过 XPath 而求助于 XQuery 之类的工具。

XQuery

既然 XQuery 天生支持 XPath 并将其作为 XQuery 语法的一部分,XQuery 显然能完成 XPath 所能完成的任何任务。但是 XQuery 是图灵完备的(Turing-complete),可以被看作是一种通用语言,因而很容易克服 XPath 的诸多局限,但代价是复杂性略有增加。

概述

XQuery 采用一种简单的语法,混合了 XML、XPath、注释、函数以及将其结合在一起的专用表达式语法。XQuery 代码完全由表达式组成,没有语句。所有的值都是序列,对于这种语言来说简单性是最重要的。因此表达式 Hi 和 2 * 2 都是合法的 XQuery 代码,不需要任何准备或者修改就能执行。XQuery 是一种高端的、强类型的函数语言(没有副作用),非常适合表达从 XML 文档或者大型 XML 存储库(repository)中获取数据的查询。最后一点,它和 SQL 非常类似。但是 XQuery 还额外提供了表达对结果集进行任意转换的功能。如同从 XML 文档中检索数据应该使用 XPath 一样,从大型 XML 存储库中检索和转换数据时则应该使用 XQuery。

转换结果集

XPath 最突出的局限性是没有提供任何办法转换结果集。假设需要将前面 XPath 查询(清单 2)返回的结果按照字母顺序排列,如清单 3 所示。

清单 3. 按字母顺序排列的结果
Serafina
Solis

使用 XPath 无法做到。此时必须使用其他语言(比如 XQuery)编写代码或者使用某种专门的私有 XPath 扩展来对结果排序。

另一方面,XQuery 允许对结果排序或者将其转换成 HTML、CSV、SQL 及其他任何基于文本的格式。XQuery 最常用的转换类型是 XML 到 XML 的转换。通常大型的 XML 数据库包含有客户端应用程序不需要的、大量复杂的、互相纠缠的 XML 文档。XQuery 允许客户端精确描述希望服务器返回的 XML 文档类型。通过提供 XQuery 接口,服务器可以避免以多种模式保存数据。此外,使用 XQuery 转换客户端数据也通常比用 Perl、Java 或其他常用计算机语言转换简单快捷得多。当然,在当前的实现中检索数据的同时使用 XQuery 转换数据,要比以后用 XSLT 转换要快得多。

为了同时输入记录选择条件和结果转换指令,XQuery 提供了被称为 FLWOR(读作 “flower”)表达式的特性。这个缩写词中的字母分别代表forletwhereorder by 和 return。这是组成 FLWOR 表达式的元素。FLOWR 表达式至少包含其中的部分元素,大体上按照缩写词所预示的顺序。所有 FLOWR 表达式都以 for 或 let 表达式开始,以 return 表达式结束。如果熟悉 SQL,您可能已经明白我前面所说的意思了。下面是一个简单的 FLOWR 表达式,借用了 Edwin Markham 的诗 “Outwitted”(如清单 4 所示)。

清单 4. 简单的 FLWOR 表达式
let $xml:=
<a>
<one>She drew a circle that shut me out</one>
<two>Heretic rebel, a thing to flout</two>
</a> return $xml//one/text() (: Result
"She drew a circle that shut me out"
:)

清单 5 展示如何将一个简单 FLOWR 表达式应用于 清单 1 中的 XML(为了简单起见,清单中用 _XML from Listing 1_ 代替了真正的 XML)。

清单 5. 简单的 FLWOR 表达式
let $xml:= _XML from Listing 1_
for $user in $xml//user[age lt 18]
order by $user/name/last
return $user/name/last/text() (: Result
Serafina
Solis
:)

如果希望查询返回 HTML 片段并把结果表示成有序列表,可使用清单 6 所示的 XQuery。

清单 6. 输出 HTML 有序列表的 FLWOR 表达式
let $xml:= _XML from Listing 1_
return
<ol>{
for $user in $xml//user[age lt 18]
order by $user/name/last
return <li>{$user/name/last/text()}</li>
}</ol> (: Result
<ol><li>Serafina</li><li>Solis</li></ol>
:)

请注意 清单 6 中 XML 和 XQuery 是如何直观有效地结合在一起的。

 

回页首

表示更复杂的记录选择条件

除了转换检索的数据外,使用 XQuery 查找数据也比 XPath 好得多。XQuery 和 XPath 经常重叠,可以帮助程序员更好地表达查询。比如,清单 7 把 XPath 表达式片段 age lt 18 放到了 FLWOR 表达式的 where 子句中。

清单 7. 在 XQuery 中使用 XPath 约束
let $xml:= _XML from Listing 1_
return
<ol>{
for $user in $xml//user
where $user/age lt 18
order by $user/name/last
return <li>{$user/name/last/text()}</li>
}</ol>

清单 7 中的表达式的结果和 清单 6 中表达式的结果完全一样。但 XQuery where 子句要比 XPath 表示约束的语法灵活得多。XQuery where 子句可以包含任意复杂的嵌套表达式,甚至可以包含函数调用。XQuery 对于记录选择表达式没有任何限制。

 

回页首

使用函数和递归

XPath 不支持函数,但 XQuery 提供了一批重要的内置函数和运算符,而且还允许用户定义自己的函数。XQuery 函数是强类型的,支持递归,可声明为内部函数或外部函数。内部函数是函数体紧跟函数声明之后的标准函数。外部函数是一种开放实现的函数声明类型,用户可以用不同的编程语言定义函数体。

虽然递归不一定是开发人员执行日常任务的最佳方法,但是对于包含多层嵌套节点的 XML 来说非常方便。比如清单 8 中定义的 transform-names 函数。

清单 8. 修改 XML 文档中节点名称的函数
(: Part 1 :)
define function transform-names($node as node()) as node() {
element{replace(name($node), "_", "-")} {
$node/text(), for $subnode in $node/* return transform-names($subnode)
}
} (: Part 2 :)
let $xml:=
<item>
<item_type>book</item_type>
<contributors>
<author>
<first_name>Charles</first_name> <last_name>Edward</last_name>
<home_address>
<home_street>206 S. Solomon St.</home_street>
<home_city>New Orleans</home_city> <home_state>LA</home_state>
<home_zip>70119</home_zip>
</home_address>
</author>
<artist> <last_name>Salinas</last_name>
</artist>
</contributors>
</item>
return transform-names($xml) (: Result
<item>
<item-type>book</item-type> <contributors>
<author>
<first-name>Charles</first-name>
<last-name>Edward</last-name>
<home-address> <home-street>206 S. Solomon St.</home-street>
<home-city>New Orleans</home-city>
<home-state>LA</home-state>
<home-zip>70119</home-zip> </home-address>
</author>
<artist>
<last-name>Salinas</last-name>
</artist> </contributors>
</item>
:)

transform-names 函数是 清单 8 中的第一段代码,可以接受任何复杂的 XML 文档或者节点。对于每个 XML 标记名,该函数将其中的下划线 (_) 该为连字符 (-)。

在这种情况下执行递归使得遍历文档结构变得非常简单。而且,该函数精炼(只有 3 行代码!)、易于维护,可用于不含属性的任何 XML 文档或者节点。虽然初看起来要完全理解这个函数有点困难 —— 尤其是对于那些很少使用递归的程序员来说 —— 但是很容易猜到如果删除下划线而不是替换为连字符时应该如何修改函数。

 

回页首

表达连接(Join)

XPath 没有提供在查询中连接 XML 节点的方法。但是,和 SQL 提供了在查询中表示表连接的自然语法一样,XQuery 也提供了一种直观(至少对于 SQL 用户而言)的方法连接 XML 节点集。清单 9 说明了如何在 XQuery 中使用连接。

清单 9. XQuery 连接表达式
(: Part 1 :)
let $authors:=
<authors>
<author>
<name>Harold Abelson</name>
<books>
<isbn>978-0-07-000422-1</isbn> <isbn>978-0-262-01063-4</isbn>
</books>
</author>
<author>
<name>Paul Graham</name> <books>
<isbn>978-0-13-370875-2</isbn>
<isbn>978-0-13-030552-7</isbn>
<isbn>978-0-596-00662-4</isbn> </books>
</author>
<author>
<name>Apostolos-Paul Refenes</name>
<books> <isbn>978-0-471-94364-8</isbn>
<isbn>978-981-02-2819-4</isbn>
</books>
</author>
</authors> (: Part 2 :)
let $books:=
<books>
<book>
<title>Structure and Interpretation of Computer Programs</title>
<isbn>978-0-07-000422-1</isbn> </book>
<book>
<title>Turtle Geometry</title>
<isbn>978-0-262-01063-4</isbn>
</book> <book>
<title>ANSI Common LISP</title>
<isbn>978-0-13-370875-2</isbn>
</book>
<book> <title>On LISP</title>
<isbn>978-0-13-030552-7</isbn>
</book>
<book>
<title>Hackers and Painters</title> <isbn>978-0-596-00662-4</isbn>
</book>
<book>
<title>Neural Networks in the Capital Markets</title>
<isbn>978-0-471-94364-8</isbn> </book>
<book>
<title>Neural Networks in Financial Engineering</title>
<isbn>978-981-02-2819-4</isbn>
</book> <book>
<title>Handbook of Artificial Intelligence</title>
<isbn>978-0-201-16889-1</isbn>
</book>
<book> <title>Artificial Intelligence Programming</title>
<isbn>978-0-89859-609-0</isbn>
</book>
<book>
<title>A New Guide to Artificial Intelligence</title> <isbn>978-0-89391-607-7</isbn>
</book>
<book>
<title>Artificial Intelligence</title>
<isbn>978-0-08-034112-5</isbn> </book>
<book>
<title>Artificial Intelligence</title>
<isbn>978-0-631-18385-3</isbn>
</book> </books> (: Part 3 :)
return
<books-complete-info>{
for $book in $books/*
for $author in $authors/*
where $book/isbn = $author//isbn
and (
contains($book/title, "LISP")
or contains($book/title, "Neural"))
order by $book/title
return <book>{$book/*, $author/name}</book>
}</books-complete-info>

清单 9 的第 1 和第 2 部分将 XML 文档赋给变量 authors 和 books。books 中的一些节点和 authors 中的节点有关,book 节点的 ISBN 出现在 author 节点的列表中。

清单第 3 部分的 XQuery 连接表达式组成了一个新的 XML 文档 books-complete-info(先看看 清单 10),其中的 book 节点包含作者的姓名。

清单 9 中第 3 部分代码有几点需要注意。开始部分的两个 for 表达式向 XQuery 表明这是一个连接表达式。where 子句在概念上类似于 SQL 的连接语句。但是要注意 author 节点可能有多个 ISBN,这就要求 where 子句必须说明:“book 的 ISBN 在作者的 ISBN 之中”。更像是 SQL where 子句中的子选择,但是 XQuery 语法看起来更直观自然。当然 XQuery 表达式也更精确。

清单 10. XQuery 连接表达式的结果
<books-complete-info>
<book>
<title>ANSI Common LISP</title>
<isbn>978-0-13-370875-2</isbn> <name>Paul Graham</name>
</book>
<book>
<title>On LISP</title>
<isbn>978-0-13-030552-7</isbn> <name>Paul Graham</name>
</book>
<book>
<title>Neural Networks in the Capital Markets</title>
<isbn>978-0-471-94364-8</isbn> <name>Apostolos-Paul Refenes</name>
</book>
<book>
<title>Neural Networks in Financial Engineering</title>
<isbn>978-981-02-2819-4</isbn> <name>Apostolos-Paul Refenes</name>
</book>
</books-complete-info>
 

回页首

结束语

XPath 作为一种成熟的 DSL,应该成为您提取深藏在 XML 文档,或者存储库中的数据时的首选。但是 XPath 的设计目标不是用于处理各种类型的问题。通过本文可以看到,XQuery 在很大程度上扩展了 XPath,如果数据筛选条件很复杂,或者需要返回排序的结果集(特殊的格式化)及进行其他转换,可以选择 XQuery。

XPath与Xquery的更多相关文章

  1. XPath、XQuery 以及 XSLT 函数

    存取函数 名称 说明 fn:node-name(node) 返回参数节点的节点名称. fn:nilled(node) 返回是否拒绝参数节点的布尔值. fn:data(item.item,...) 接受 ...

  2. XPath注入笔记

    XPath注入 XQuery注入 测试语句:'or '1'='1 利用工具: Xcat介绍 Xcat是python的命令行程序利用Xpath的注入漏洞在Web应用中检索XML文档 下载地址:https ...

  3. XML, XPath, Xslt及解析/Parse

    XML及解析/Parse "Programming with libxml2 is like the thrilling embrace of an exotic stranger.&quo ...

  4. 转载--SQL Server 2005的XQuery介绍

    原文地址: http://bbs.51cto.com/thread-458009-1-1.html   引用: 摘要 本文介绍了SQL Server 2005能够支持的XQuery的各方面特性如FLW ...

  5. Querying Microsoft SQL Server 2012 读书笔记:查询和管理XML数据 2 -使用XQuery 查询XML数据

    XQuery 是一个浏览/返回XML实例的标准语言. 它比老的只能简单处理节点的XPath表达式更丰富. 你可以同XPath一样使用.或是遍历所有节点,塑造XML实例的返回等. 作为一个查询语言, 你 ...

  6. XPath教程

    XPath 简介 XPath 是一门在 XML 文档中查找信息的语言.XPath 可用来在 XML 文档中对元素和属性进行遍历. XPath 是 W3C XSLT 标准的主要元素,并且 XQuery ...

  7. XML 的 XPath 语法

    XPath 是 XML 路径语言(XML Path Language),用来确定XML文档中某部分位置的语言.无论是什么语言什么框架,几乎都可以使用 XPath 来高效查询 XML 文件. 本文将介绍 ...

  8. DB2错误码信息

    00 完全成功完成 表 3  01 警告 表 4  02 无数据 表 5  07 动态 SQL 错误 表 6  08 连接异常 表 7  09 触发操作异常 表 8  0A 功能部件不受支持 表 9  ...

  9. xml in SQL

    几年前,学习html时,顺便把xml也学了哈,知道了xpath和xquery的概念,可都没去落实,下面这篇文章,可以学习学习 http://www.cnblogs.com/huyong/archive ...

随机推荐

  1. JavaScript Array(数组) 对象

    更多实例 合并两个数组 - concat() 合并三个数组 - concat() 用数组的元素组成字符串 - join() 删除数组的最后一个元素 - pop() 数组的末尾添加新的元素 - push ...

  2. angular.js 数字

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <script sr ...

  3. Tenth Line

    How would you print just the 10th line of a file? For example, assume that file.txt has the followin ...

  4. prototype/constructor/__proto__之constructor。

    1.constructor的字面意思就是构造.它是对象的一个属性,它对应的值是该对象的“构造者” //一.构造函数实例化的对象的constructor function Cmf(n,m){ this. ...

  5. Win8.1 64bit安装Genymotion模拟器

    其实安装并不复杂,只要环境正常,此事并不难.但估计最坏的情况都被我撞上了,才折腾了差不多一天的 那我有哪些环境不正常呢? 破解了系统主题 Device Install Service服务未启动 下面来 ...

  6. IE 6最小最大宽度与高度的写法

    最小最大宽度,最小最大高度,这是CSS很常见的一个要求.在现代浏览器中,一个 min-height,min-width 就可以解决问题,但是在IE系列,比如IE6则比较繁琐一点.下面总结一些IE 6下 ...

  7. Webservices-2.C#创建web服务,及引用访问、代码访问

    注:web服务简介Webservices-1.web服务定义简介 以下均以C#语言为例 一.创建web服务(简单介绍,主要讨论客户端引用) 打开VS创建网站项目,在网站项目中添加“WEB服务(ASMX ...

  8. 从一到二:利用mnist训练集生成的caffemodel对mnist测试集与自己手写的数字进行测试

    通过从零到一的教程,我们已经得到了通过mnist训练集生成的caffemodel,主要包含下面四个文件: 接下来就可以利用模型进行测试了.关于测试方法按照上篇教程还是选择bat文件,当然python. ...

  9. vmware中ubuntu更新内核后无法进入桌面,鼠标“漂移”滑动

    问题背景: 我机子上是在vmware下安装了ubuntu12.04,今天正在ubuntu下工作,结果提示内核有更新,手贱的就点了个OK,开始更新,更新完重启.结果,问题来了,刚开始系统启动,进入系统登 ...

  10. 转:PHP开发者应了解的24个库

    原文来自于:http://blog.jobbole.com/54201/ 作为一个PHP开发者,现在是一个令人激动的时刻.每天有许许多多有用的库分发出来,在Github上很容易发现和使用这些库.下面是 ...