XPath即为XML路径语言(XML Path Language),这是一篇XPath的笔记。

概述

XPath的主要功能是定位XML文档中的某部分内容,换句话说,就是确定一条路,使得电脑能够顺着这条路找到你想要的节点。

语法

节点

节点是XPath中的基本单位,以下几种都属于节点:

1
2
3
<bookstore> <!-- 文档节点 -->
<author>J K. Rowling</author> <!-- 元素节点 -->
lang="en" <!-- 属性节点 -->

而节点中的数据被称为原子值 ,比如上述例子中,J K. Rowling与“en”都属于原子值。

而节点之间的关系 分为父(Parent)、子(Children)、兄弟(Sibling)、先辈(Ancestor)与后代(Descendant)。举个例子,在如下文档中:

1
2
3
4
5
6
7
8
<bookstore>
<book>
<title>Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
</bookstore>

<title>的父节点是<book>,而先辈节点是<book>与<bookstore>;<bookstore>的子节点是<book>,而后代节点是<book>、<title>、<author>、<year>以及<price>。

基本语法

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
<book>
<title lang="eng">Harry Potter</title>
<price>29.99</price>
</book>
<book>
<title lang="eng">Learning XML</title>
<price>39.95</price>
</book>
</bookstore>

在以上文档中,假如我们需要匹配所有<title>元素,那就可以使用以下语法:

1
/bookstore/book/title

这就是XPath的最核心语法,是不是一看就懂。当然,在匹配过程中,为了方便地操作,还有一些路径表达式可以选用:

表达式 描述 实例
nodename 选取此节点的所有子节点。 bookstore
/ 从根节点选取。 /bookstore
// 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。 //title
. 选取当前节点。 //title/.
.. 选取当前节点的父节点。 //title/..
@ 选取属性。 //@lang

在匹配过程中,假如我们要匹配到一些未知节点,或是不精确匹配,就可以用通配符 来匹配未知节点:

通配符 描述 实例
* 匹配任何元素节点。 /bookstore/*
@* 匹配任何属性节点。 //title/@*
node() 匹配任何类型的节点。 //book/node()

在匹配过程中,如果要选取若干路径,则可以用 “|” 运算符连接:

1
//book/title | //book/price

谓语

谓语相当于在匹配的过程中加入一些限定条件,起到过滤地作用。看几个例子就能明白了:

表达式 结果
/bookstore/book[1] 选取属于 bookstore 子元素的第一个 book 元素。(注意,是从1开始,而不是从0开始)
/bookstore/book[last()] 选取属于 bookstore 子元素的最后一个 book 元素。
/bookstore/book[last()-1] 选取属于 bookstore 子元素的倒数第二个 book 元素。
/bookstore/book[position() < 3] 选取最前面的两个属于 bookstore 元素的子元素的 book 元素。
//title[@lang] 选取所有拥有名为 lang 的属性的 title 元素。
//title[@lang=‘eng’] 选取所有 title 元素,且这些元素拥有值为 eng 的 lang 属性。
/bookstore/book[price>35.00] 选取 bookstore 元素的所有 book 元素,且其中的 price 元素的值须大于 35.00。
/bookstore/book[price>35.00]//title 选取 bookstore 元素中的 book 元素的所有 title 元素,且其中的 price 元素的值须大于 35.00。

如果我们已经确定了一个节点,但要顺着这个节点匹配与它相关的其他值,那就可以通过轴来进行查找。比如我们要匹配bookstore下的所有title节点,但我们不清楚title的具体位置,就可以用如下表达式:

1
/bookstore/descendant::title

其中,/descendant::title即是一段轴表达式,表示匹配后代中所有的title元素,轴表达式有以下多种选择:

结果
ancestor 选取当前节点的所有先辈(父、祖父等)。
ancestor-or-self 选取当前节点的所有先辈(父、祖父等)以及当前节点本身。
attribute 选取当前节点的所有属性。
child 选取当前节点的所有子元素。
descendant 选取当前节点的所有后代元素(子、孙等)。
descendant-or-self 选取当前节点的所有后代元素(子、孙等)以及当前节点本身。
following 选取文档中当前节点的结束标签之后的所有节点。
following-sibling 选取当前节点之后的所有兄弟节点
namespace 选取当前节点的所有命名空间节点。
parent 选取当前节点的父节点。
preceding 选取文档中当前节点的开始标签之前的所有节点。
preceding-sibling 选取当前节点之前的所有同级节点。
self 选取当前节点。

节点测试函数

由于函数有很多,所以这里只稍微介绍几个:

comment()

对注释节点返回 True。如following::comment() 可以选择所有出现在上下文节点之后的注释节点。

text()

对文本节点返回 True。如child::text() 选择属于上下文节点子级的文本节点。

empty()

如果参数值是空序列则返回 True。如 //book[empty(child::title)]/price选择所有不含title的book的price。

类型

XPath是强类型的语言。在查询计划的编写和执行过程中,数据类型扮演着重要的角色。

序列类型

这里举两个函数:

codepoints-to-string(int arg[])

该函数将序列中的数值(Unicode代码点)转换为字符串。参数 arg 是一个由0或多个整数值构成的序列,返回值是一个字符串。

codepoints-to-string((88, 81, 117, 101, 114, 121)) 返回 “XQuery”。

string-to-codepoints(string arg)

该函数将参数中的字符串转换为Unicode代码点。参数 arg 是一个空序列或者一个字符串,返回值是一个由0或多个整数值构成的序列。

string-to-codepoints("XQuery") 返回 (88, 81, 117, 101, 114, 121) 。

类型转换

与大多数一样,XPath也支持隐式类型转换与显式类型转换。这边介绍一下几个显式类型转换的相关操作符:

cast as

可以使用 cast as 操作符进行显式类型转换。比如,表达式 "123" cast as xs:integer 可以将字符串 123 转换为整型值。

castable as

可以使用 castable as 操作符判断是否能够成功地进行显式类型转换,但并不进行类型转换。返回值为 true 或 false。

instance of

如果输入数据是目标类型的实例,则返回 true,否则返回 false。

  1. 对于简单数据类型:通过限制派生的数据类型的值 instance of 原数据类型 = true

  2. 对于用户定义的复杂类型:通过扩展派生的数据类型的值 instance of 原数据类型 = true