XML/XPath

維基教科書,自由的教學讀本
< XML

XML > XPath


XPath[編輯]

學習目標[編輯]

完成本章的學習後,您將能夠:

  • 形成這樣的概念:一個XML文檔是一棵節點樹
  • 在XML文檔中引用元素組
  • 了解簡寫與非簡寫XPath語法的不同
  • 了解絕對路徑與相對路徑的不同
  • 使用XPath謂詞和函數提煉出一個XPath節點集

概述[編輯]

在前面的章節中您已經學習了XSL。進行XSL轉換時基本上都必須引用XML文檔中的節點。目前常使用一種簡單易懂

的語法來引用XML文檔中的節點。這種語法就是XPath。當然XPath具有更多我們尚未利用的特徵和能力。本章將深 入介紹XPath這種XML的路徑語言,常用於引用XML文檔中的節點。

本章將對XPath語法進行簡要的概括,但這足以使您了解它的基本概念。想全面地深入認識XPath,請察看最新版

本的標準:

http://www.w3.org/TR/xpath

您也可以暫時鬆一口氣,因為本章不會用到XML schemas。介紹XPath的概念時無須使用XML schemas。而能夠展

現XPath能力的則是XSL,在XSL中常常使用XPath。

XPath[編輯]

在*nix或Windows系統中複製一個文件或進入一層目錄時,通常會在命令提示符後輸入諸如「/home/darnell/」

或「C:\MyFiles\」之類來引用文件夾。藉此您可以進入或引用計算機文件系統中的文件夾。XML使用類似的方法來 引用XML文檔中的元素。這種特殊的語法就是XPath,即XML路徑語言(XML Path Language)的縮寫。

儘管XPath用於引用XML樹的節點,它本身並不以XML格式書寫。對於W3C,這是一個明智的做法,因為用XML表示

路徑信息非常困難。任何形成XML語法的字符都必須進行轉義,以免在處理時與XML混淆。而Xpath卻十分簡潔,可 以有針對性地引用XML樹中節點,可以避免不必要的冗長表示。

XML 的樹形結構[編輯]

我們可以把一個XML文檔看作是一個樹形結構,文檔的頂端是樹根。樹上的每個元素都可稱為節點(node)。頂層

元素稱為「根節點」,所有包含在其中的標籤都是它的後繼節點。圖9-1是一個HTML文檔,顯示了XML文檔的樹形結構。

http://ebiz.terry.uga.edu/~darford/XPath-9_1.PNG

圖9-1一個基本HTML文檔的樹形模型

節點關係[編輯]

在樹形結構中,節點<html> 是元素 <head> 和 <body> 的父節點(parent)。 它也是除

「根」元素外其他所有節點的祖先節點(ancestor),根元素沒有祖先節點。本例中,標籤<p> 是 <body>的子節點(child)。 標籤 <p> 也可被認為是「根」元素、節點<html>,和 <body>的後繼節點(descendant),因為它在樹中處於較低級的位置。如果兩個節點擁有同一個父節點, 例如<head> 和<body>,它們將被稱為兄弟節點(siblings)。

就像在XML編輯器中看到的那樣,有時我們把XML文檔看成是序列化文檔。這樣有助於理解前趨節點和後續節點的概

念。按照文檔順序,如果一個節點位於另一個節點之前,那麼稱前者為後者的前趨節點(precede)。同樣,如果一 個節點位於另一個節點之後,那麼稱前者為後者的後續節點(follow)。祖先節點和子孫節點是不考慮是否前趨於 某一節點或後續於某一節點的。在後面討論軸(axis)時這些概念會變得清晰些。

簡寫的XPath語法與非簡寫的XPath語法[編輯]

建立XPath可使節點的引用變得簡潔,同時保持進行多選項的搜索的能力。大多數XPath的使用者會搜索某一特定

節點的子節點、父節點或屬性節點。因為這樣的行為比較普遍,在引用這些經常被搜索的節點時可以使用簡寫的語 法。下面是一個樹形的XML文檔(具有葉子和分支),它將用於表示不同種類的語法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

<?xml version="1.0" encoding="UTF-8"?>
<trunk name="the_trunk">
<bigBranch name="bb1" thickness="thick">
<smallBranch name="sb1">
<leaf name="leaf1" color="brown" />
<leaf name="leaf2" weight="50" />
<leaf name="leaf3" />
</smallBranch>
<smallBranch name="sb2">
<leaf name="leaf4" weight="90" />
<leaf name="leaf5" color="purple" />
</smallBranch>
</bigBranch>
<bigBranch name="bb2">
<smallBranch name="sb3">
<leaf name="leaf6" />
</smallBranch>
<smallBranch name="sb4">
<leaf name="leaf7" />
<leaf name="leaf8" />
<leaf name="leaf9" color="black" />
<leaf name="leaf10" weight="100" />
</smallBranch>
</bigBranch>
<bigBranch name="bb3" thickness="thin">
<smallBranch name="sb5" color="lightBrown" >
<leaf name="leaf11" />
<leaf name="leaf12" />
</smallBranch>
<smallBranch name="sb6" thickness="thin">
<leaf name="leaf13" weight="2" />
<leaf name="leaf14" color="red" />
<leaf name="leaf15" />
</smallBranch>
<smallBranch name="sb7">
<leaf name="leaf16" />
<leaf name="leaf17" color="red" />
</smallBranch>
</bigBranch>
</trunk>

圖9-2 tree. xml – XML 頁示例

以下是其中一些XPath定位路徑的示例,包括簡寫的和未簡寫的XPath:


示例1:

意義: 在上面文檔中所有的 <leaf> 元素都是<smallBranch> 元素的子節點,而 <smallBranch>元素是<bigBranch>元素的子節點,<bigBranch>元素是trunk的子節 點,trunk又是根的子節點。
簡寫: /trunk/bigBranch/smallBranch/leaf
未簡寫: /child::trunk/child::bigBranch/child::smallBranch/child::leaf

示例 2:

意義: <bigBranch> 元素的name屬性為「bb3」,是trunk元素的子節點,trunk元素是根的子節點。
簡寫: /trunk/bigBranch[@name=』bb3』]
未簡寫: /child::trunk/child::bigBranch[attribute::name=』bb3』]

注意示例中如何利用謂詞來指定所需要的bigBranch。這使搜索範圍縮小,只搜索那些滿足謂詞條件的bigBranch

節點。謂詞是方括號中XPath語句的一部分。本例中謂詞要求bigBranch節點的name屬性值為「bb3」。

以上兩個示例是假定指定從根開始的路徑。下面的示例則指定從一個<smallBranch>節點開始的路徑:


示例 3:

意義:當前<smallBranch&gt節點的父節點。(注意本例是相對於 <smallBranch>節點來看的)
簡寫: ..
未簡寫: parent::node()

採用未簡寫語法時必須注意,被調用父節點或子節點的後面應該跟着兩個冒號(::),冒號之前的節點稱為軸

(axis)。後面的小節將會講解更多關於軸的知識。

現在正好來解釋一下定位路徑(location path)的概念。定位路徑是指為到達指定節點所採取的一系列定位步驟

(location steps)。定位步驟是XPath語句的一部分,被字符「/」隔開。它們是在尋找指定節點過程所經過的 每一步。

定位步驟由3部分構成:軸(axis)(子節點,父節點,子孫節點等等),節點測試(node test)(節點名稱,

或者是可返回一個或多個節點的函數),以及一系列謂詞(檢驗返回的節點以縮小搜索結果的範圍,去掉那些沒有通 過謂詞檢驗的節點)。

因此,在一個定位路徑中每一個定位步驟都會返回一個節點列表。如果路徑在某一定位步驟沒有結束,那麼將會對

本次定位步驟所返回的所有節點執行下一步操作。

相對路徑 與 絕對路徑[編輯]

用Xpath可以指定兩種路徑,一種情況是 已經「處於一個節點之中」的路徑,另一種情況則是選擇從根節點開始的

路徑。熟悉HTML網站的人會發現,HTML超級連結也是使用同樣的方法來引用其它文件的。在HTML中,可以為超級鏈 接指定一個絕對路徑(absolute path),在URL中描述該頁所在的伺服器名,文件夾和文件名。如果所引用的文 件在同一站點上,就不需要輸入伺服器名和完整的路徑信息。這被稱為是相對路徑(relative path)。這些概念 在XPath中也同樣被採用。

兩者的不同則體現在XPath表達式的開始位置是否存在字符『/』。如果有,表明這是一個絕對路徑,是從根開始的

路徑。如果沒有,表明這是一個相對路徑,只是描述當前節點與前後節點的關係,或是下一步要使用的節點。

下面是一個XSL樣式表(圖9-3),它用到了圖9-2中的樹形XML文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html"/>

<xsl:template match="/child::trunk">
<html>
<head>
<title>XPath Tree Tests</title>
</head>
<body>
<xsl:for-each select="child::bigBranch">
<xsl:call-template name="print_out" />
</xsl:for-each>
</body>
</html>
</xsl:template>

<xsl:template name="print_out">
<xsl:value-of select="attribute::name" /><br />
</xsl:template>

</xsl:stylesheet>

圖 9-3 xsl_tree.xsl – 絕對路徑和相對路徑的示例

在上面的代碼中,第5行是一個絕對連結的示例。元素『/child::trunk'』是從根元素開始指定的。第12行是一個相對連結的示例。<for-each> xsl 語句會在「當前」節點中的每一個<bigBranch> 節點上執行,而這個「當前」節點正是<trunk> 節點。

四種XPath定位路徑[編輯]

上面兩個小節介紹了定位路徑的兩類區別:簡寫路徑與未簡寫路徑,相對路徑與絕對路徑。結合這兩類概念有助於

理解XPath定位路徑。當您在朋友面前這樣談論事物時,會顯得您的思路十分有條理:

  1. 簡寫的相對定位路徑
  2. 簡寫的絕對定位路徑
  3. 未簡寫的相對定位路徑
  4. 未簡寫的絕對定位路徑
此處僅列出了4種不同的方式,通過閱讀相關材料,能夠很容易地得到上述將定位路徑分為4類的區分方式。

XPath軸[編輯]

在XPath中,有些節點需要使用未簡寫的語法來進行選擇。在這種情況下,就要使用軸來指定定位路徑中的每一個定位步驟。
從樹上的任意節點出發,都有13個軸可以使用,它們是:


含義
ancestor:: 由當前節點向上,從父節點至根節點
ancestor-or-self:: 由當前節點向上,從當前節點到父節點直至根節點 attribute:: 當前節點的屬性(Attributes of the current node) child:: 當前節點的直接子節點(Immediate children of the current node) descendant:: 當前節點的子孫節點(包括子節點的子節點) descendant-or-self:: 當前節點的子孫節點以及當前節點本身 following:: 當前節點的後續節點(子節點除外) following-sibling:: 與當前節點處於同一層的後續節點(子節點除外) namespace:: 當前節點的XML 命名空間 parent:: 當前節點的直接父節點 preceding:: 當前節點的前趨節點(子節點除外) preceding-sibling:: 與當前節點處於同一層的前趨節點(子節點除外) self:: 當前節點

XPath謂詞(predicate)與函數(function)[編輯]

有時為了進一步篩選,需要在XPath定位路徑中使用謂詞。通常一個定位路徑的返回值是一個節點集。謂詞是一個

小型表達式,可以對節點集中的節點進行判斷。如果表達式判斷的結果是「假」,那麼就將該節點捨去。下面是一個 示例:

//p[@class=『alert』]

上面的表達式對文檔中的標籤進行檢驗,判斷它們的「class」屬性是否為「alert」。只有那些滿足這一條件的

標籤才能夠進入該定位路徑所選出的節點集。

下面的示例則在謂詞表達式中使用了一個函數來獲取當前選擇節點(也稱為場景節點context node)的信息:


/book/chapter[position()=3]

結果是選擇書中處於第三位的章節(chapter)。為了能夠返回正確值,當前的<book>元素至少應該含有三個

<chapter>元素。同時請注意,函數position() 返回的是一個整數值。

XPath規範中有許多函數。想查看完整的函數列表,請閱讀W3C規範。
以下是一些常用的函數:

數值型last() – 返回當前節點集中最後一個節點 數值型position() – 返回被測試的當前選擇節點的位置 數值型count(node-set) – 返回節點集的節點數

布爾型starts-with(string, string) – 如果函數中前一個字符串參數的起始N個字符等於後一個字符串參數則返回真值 布爾型contains(string, string) – 如果函數中前一個字符串包含後一個字符串則返回真值 數值型sum(node-set) – 返回節點集中所有數值節點的數值總和 數值型floor(number) – 返回不超過其值的最大整數 數值型ceiling(number) – 返回不小於其值的最小整數 數值型round(number) – 返回四捨五入後的整數

練習[編輯]

下面的練習可以提高您使用XPath的技巧。需要用到tree.xml文件和xsl-tree.xsl文件:
修改並複製xsl-tree.xsl文件,在複製後的文件名中加入相應題號。
  1. 找出thickness屬性值為「thick」的bigBranch元素,打印其name屬性值。
  2. 找出每個bigBranch的父節點,打印其name屬性值。
  3. 找出帶有color屬性的leave節點,打印其color屬性值。