XML/XPath
XPath
編輯學習目標
編輯完成本章的學習後,您將能夠:
- 形成這樣的概念:一個XML文檔是一棵節點樹
- 在XML文檔中引用元素組
- 了解簡寫與非簡寫XPath語法的不同
- 了解絕對路徑與相對路徑的不同
- 使用XPath謂詞和函數提煉出一個XPath節點集
概述
編輯- 在前面的章節中您已經學習了XSL。進行XSL轉換時基本上都必須引用XML文檔中的節點。目前常使用一種簡單易懂
的語法來引用XML文檔中的節點。這種語法就是XPath。當然XPath具有更多我們尚未利用的特徵和能力。本章將深 入介紹XPath這種XML的路徑語言,常用於引用XML文檔中的節點。
- 本章將對XPath語法進行簡要的概括,但這足以使您了解它的基本概念。想全面地深入認識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 |
<?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>節點的父節點。(注意本例是相對於 <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 |
<?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定位路徑。當您在朋友面前這樣談論事物時,會顯得您的思路十分有條理:
- 簡寫的相對定位路徑
- 簡寫的絕對定位路徑
- 未簡寫的相對定位路徑
- 未簡寫的絕對定位路徑
- 此處僅列出了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文件,在複製後的文件名中加入相應題號。
- 找出thickness屬性值為「thick」的bigBranch元素,列印其name屬性值。
- 找出每個bigBranch的父節點,列印其name屬性值。
- 找出帶有color屬性的leave節點,列印其color屬性值。