XPath查詢XML文檔的注意事項
<?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 |