<?xml version="1.0" encoding="UTF-8" ?> <bk:books xmlns:bk="urn:xmlns:25hoursaday-com:my-bookshelf" on-loan="yes" > <bk:book publisher="IDG books" on-loan="Sanjay" > <bk:title>XML Bible</bk:title> <bk:author>Elliotte Rusty Harold</bk:author> </bk:book> <bk:book publisher="QUE"> <bk:title>XML By Example</bk:title> <bk:author>Benoit Marchal</bk:author> </bk:book> </bk:books> |
缩写 | 轴 |
---|---|
. | self::node() |
.. | parent::node() |
// | /descendent-or-self::node()/ |
@ | attribute:: |
缩写
|
完整查询
|
查询结果
|
---|---|---|
//*[1] | /descendent-or-self::node()/child::*[position()=1] | 选择文档中每个节点的第一个子节点。 |
(//*)[1] | (/descendent-or-self::node()/child::*)[position()=1] | 选择文档中第一个节点。 |
提高我们的数学技能
涉及关系或算术运算符和字符串的查询通常导致与直觉不相符的结果。XPath 将涉及关系或算术运算符的表达式中的所有操作数转换为数字。不完全是数字值的字符串将转换为 NaN(不是一个数)。下表显示某些 XPath 表达式、表达式隐式转换成的内容以及表达式的结果。
表达式 | 隐式转换 | 结果 |
---|---|---|
'5' + 7 | 5 + 7 | 12 |
'5' + '7' | 5 + 7 | 12 |
5 + 'a' | 5 + NaN | NaN |
'5' < 7 | 5 < 7 | True |
'5' < '7' | 5 < 7 | True |
'5' < 'b' | 5 < NaN | False |
'a' < 'b' | NaN < NaN | False |
'a' > 'b' | NaN > NaN | False |
<Root> <Numbers> <Integer value="4" /> <Integer value="2" /> <Integer value="3" /> </Numbers> <Numbers> <Integer value="2" /> <Integer value="3" /> <Integer value="6" /> </Numbers> </Root> |
表达式 | 结果 | 解释 |
---|---|---|
Root/Numbers[Integer/@value > 4 - 1] | <Numbers> <Integer value="4" /> <Integer value="2" /> <Integer value="3" /> </Numbers> <Numbers> <Integer value="2" /> <Integer value="3" /> <Integer value="6" /> </Numbers> |
选择文档中的所有 <Numbers> 元素,其中“至少一个”<Integer> 元素具有值大于 4 减 1 的 value 属性。 |
Root/Numbers[ 1 + Integer/@value > 4] | <Numbers> <Integer value="4" /> <Integer value="2" /> <Integer value="3" /> </Numbers> |
选择文档中的所有 <Numbers> 元素,其中 1 加上具有值大于 4 的 value 属性的“第一个”<Integer> 元素。 |
如果 XPath 是代数结合的,则两种查询将返回同样的结果。
何时集合不是一个集合?
虽然节点集合是无序的集合,就象数学(或您喜欢的编程语言)中的集合一样,但是处理它们通常与处理数学意义上的集合不同。XPath 中的某些操作在处理节点集合时使用“第一”语义,而其他操作使用“任意”语义。“第一”语义意味着该操作的节点集合的值从集合中的第一个节点获得,而“任意”语义则意味着节点集合中的操作取决于集合中的任何节点是否满足该条件。标题为“提高数学技能”的小节将介绍使用“任意”和“第一”语义的情况。
XPath 节点集合与数学集合不同的另一个特征是 XPath 不直接提供机制以执行集合操作(如子集、交集或对称差集)。Michael Kay(XSLT Programmer's Reference 2nd edition 的作者)最早发现如何使用 count() 函数和联合运算符 | 来模拟缺少的集合运算符。下面列出了对上面一节中的 XML 文档执行集合操作的 XSLT 样式表及其输出。
样式表
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" > <xsl:output method="text" /> <xsl:variable name="a" select="/Root/Numbers[1]/Integer/@value"/> <xsl:variable name="b" select="/Root/Numbers[1]/Integer/@value[. > 2]"/> <xsl:variable name="c" select="/Root/Numbers[1]/Integer/@value[. = 3]"/> <xsl:template match="/"> SET A: { <xsl:for-each select="$a"> <xsl:value-of select="." />, </xsl:for-each> } SET B: { <xsl:for-each select="$b"> <xsl:value-of select="." />, </xsl:for-each> } SET C: { <xsl:for-each select="$c"> <xsl:value-of select="." />, </xsl:for-each> } a UNION b: { <xsl:for-each select="$a | $b"> <xsl:value-of select="." />, </xsl:for-each> } b UNION c: { <xsl:for-each select="$b | $c"> <xsl:value-of select="." />, </xsl:for-each> } a INTERSECTION b: { <xsl:for-each select="$a[count(.|$b) = count($b)]"> <xsl:value-of select="." />, </xsl:for-each> } a INTERSECTION c: { <xsl:for-each select="$a[count(.|$c) = count($c)]"> <xsl:value-of select="." />, </xsl:for-each> } a DIFFERENCE b: { <xsl:for-each select="$a[count(.|$b) != count($b)] | $b[count(.|$a) != count($a)]"> <xsl:value-of select="." />, </xsl:for-each> } a DIFFERENCE c: { <xsl:for-each select="$a[count(.|$c) != count($c)] | $c[count(.|$a) != count($a)]"> <xsl:value-of select="." />, </xsl:for-each> } a SUBSET OF b: { <xsl:value-of select="count($b | $a) = count($b)"/> } b SUBSET OF a: { <xsl:value-of select="count($b | $a) = count($a)"/> } </xsl:template> </xsl:stylesheet> |
SET A: { 4, 2, 3, } SET B: { 4, 3, } SET C: { 3, } a UNION b: { 4, 2, 3, } b UNION c: { 4, 3, } a INTERSECTION b: { 4, 3, } a INTERSECTION c: { 3, } a DIFFERENCE b: { 2, } a DIFFERENCE c: { 4, 2, } a SUBSET OF b: { false } b SUBSET OF a: { true } |
节点集合和数学集合之间差异的最后一点是节点集合通常是有序的。W3C XPath 建议将它们描绘为无序的,但是 XSLT 确实指定了节点集合的顺序。
标识危机
在 XPath 中,没有直接确定节点标识或不同节点集合中的等效节点的构造。不直接支持比较,例如由 /bk:books 返回的节点是否与由 /bk:books/bk:book[1]/parent::* 返回的节点相同。在节点集合上使用 = 运算符的比较不将节点集合作为一个整体进行比较,而是使用“任意”语义。从 W3C XPath 建议:
“如果要比较的两个对象都是节点集合,则当且仅当第一个节点集合中有一个节点且第二个节点集合中有一个节点时,该比较才为 true,这样在两个节点的字符串值上进行比较的结果才为 true。”
为了解释清楚这一点,以下是显示从简介的 XML 分类格式中执行有关节点集合比较操作结果的表格。请注意这些初看起来就象相互矛盾的结果。
表达式 | 结果 | 解释 |
---|---|---|
//bk:book = /bk:books/bk:book[1] | TRUE | 是否 //bk:book 中至少有一个节点与 /bk:books/bk:book[1] 中的另一个节点具有同样的字符串值? |
//bk:book != /bk:books/bk:book[1] | TRUE | 是否 //bk:book 中至少有一个节点与 /bk:books/bk:book[1] 中的另一个节点具有不同的字符串值? |
not(//bk:book = /bk:books/bk:book[1]) | FALSE | 问题“是否//bk:book 中至少有一个节点与 /bk:books/bk:book[1] 中的另一个节点具有同样的字符串值?”的相反答案。 |
表达式 | 结果 |
---|---|
/NonExistentNode + 5 | NaN |
/NonExistentNode = 5 | False |
/NonExistentNode != 5 | False |
concat(/NonExistentNode, "hello") | "hello" |
/Root[@nonExistentAttribute] | 不返回结果 |
/Root[@nonExistentAttribute < 5] | 不返回结果 |
/Root[@nonExistentAttribute > 5] | 不返回结果 |
urn:xmlns:25hoursaday-com:my-bookshelf http://www.w3.org/XML/1998/namespace |