9.3 XPath基础语法

XPath语言使用路径表达式来定位XML文档中的节点或节点集,每个XPath表达式总由多个步(step)组成,多个步之间用斜线分隔。

下面是一个常见的XPath表达式:

alt

上面的XPath表达式匹配XML文档里<list…/>根元素下<book…/>子元素所包含的<name…/>子元素。对于上面的XPath表达式而言,list、book和name都称为步(step)。

根据上面的XPath表达式的内容,读者很容易将步和元素名或属性名等同起来,但实际上,XPath中的步支持更多的语法选项。

XPath中步的完整语法格式如下:

alt

由上面的语法格式可以看出,每个步都由3个部分组成:

alt 轴:用于定义所选节点与当前节点之间的结构关系,例如父子、后代等。

alt 节点测试:用于选取指定轴内部的部分节点。

alt 限定谓语:用于对轴和节点测试所匹配的节点集进行进一步限定。

9.3.1 轴(axis)

XPath的步使用轴来定义所选节点与当前节点之间的结构关系,表9.2显示了XPath所支持的各种轴及其含义。

表9.2 XPath所支持的轴及其含义

alt

通过在步中使用轴,就可以当前节点为基础,选出与当前节点存在父子、兄弟、前后等结构关系的一批节点。由此可见,轴是XPath表达式中沿指定方向导航的一种方式。

9.3.2 节点测试(node-test)

通过在步中使用轴可以选出与当前节点存在父子、兄弟、前后等结构关系的一批节点,而接下来的节点测试则用于从指定轴所匹配的节点集中选出特定的节点。

XPath支持的常用节点测试语法如表9.3所示。

表9.3 XPath所支持的节点测试语法

alt

通过使用节点测试来识别某个轴内部的指定节点,可进一步缩小步所匹配节点集的范围。接下来,还可使用限定谓语对轴、节点测试所选出的节点进行进一步过滤。

9.3.3 限定谓语(predicate)

每个步中可以接受零个或者更多限定谓语,限定谓语用于进一步提炼所选的节点集。限定谓语应该放在方括号中。

限定谓语是一个boolean表达式,或者可以转换为boolean值的表达式,总之限定谓语表达式的值要么返回true,要么返回false。对于前面通过轴和节点测试所获得的节点集,XPath会依次将每个节点传入限定表达式中进行测试,如果该节点传入限定表达式中测试时返回true,则该节点被保留,否则将会被过滤掉。

例如如下步定义:

alt

上面的步定义首先取得当前节点的所有book子节点——这由child轴和book节点测试所决定。除此之外,上面的步定义中还包括了一个简单的限定谓语[position()=1],其中position()是一个XPath函数,它返回指定节点在其父节点中的位置,这在后面会有详细介绍。XPath会将当前节点的所有book子节点依次传入[position()=1]限定谓语中进行测试,只有该节点是其父节点的第一个子节点时该限定谓语才会返回true。也就是说,child::book[position()=1]用于选取当前节点的第一个book子节点。

大多数时候,限定谓语总是返回一个boolean值。在有些情况下,XPath允许简化限定谓语的写法:限定谓语返回一个整数值时,XPath会自动拿该整数值与当前节点的position()函数的返回值进行比较,如果返回true,则该节点将被保留。也就是说,child::book[position()=1]和child::book[1]的意义完全相同。

由于只要求限定谓语是一个boolean表达式,因此限定谓语中可以使用各种XPath函数。关于XPath函数,在后面会有更详细的介绍。

9.3.4 简化写法

如果XPath表达式中每个步都严格使用上面的语法(由轴、节点测试和限定谓语组成),那XPath表达式将变得非常复杂,因此XPath语言允许使用简化写法来定义步。

XPath的简化写法有如下几种:

省略child轴

由于child轴是XPath的默认轴,因此完全可以在定义XPath表达式时省略child轴。例如website/crazyit等同于child::website/child::crazyit。

使用@符号代替attribute轴

前面在介绍XSLT转换时已经看到过,@abc可用于代表abc属性,因此@符号可用于代替attribute轴。例如book/@isbn用于访问book元素的isbn属性,等同于child::book/attribute::isbn;book[@isbn="12345678"]等同于child::book[attribute::isbn="12345678"]。

使用双斜线(//)代表后代节点

在XPath中可使用双斜线(//)代表后代节点(包括自己),因此双斜线实际上是/descendant-or-self::node()/的简化写法,例如//book等同于/descendant-or-self::node()/child::book。

使用一个点(.)代表当前节点

这是很常用的用法,这种用法甚至可以和文件系统里一个点(.)的意义保持一致:一个点用于代表当前路径。英文点号(.)实际上是self::node()的简化写法。例如./book等同于self::node()/child::book。

使用两个点(..)代表上一级节点(父节点)

这也是很常用的用法,这种用法也可以和文件系统里两个点(..)的意义保持一致:两个点用于代表上一级路径。两个点(..)实际上是parent::node()的简化写法。例如../book等同于parent::node()/child::book。

如果每次定义步都使用轴::节点测试[限定谓语]的方式,语法格式会更一致、更严格,但这种做法会使得XPath表达式更加复杂;相反,使用上面的简化写法则更加简洁。


alt注意

对于XSLT中匹配节点的模式,只能使用child和attribute轴,而且只能使用简化写法。