XPath 詳解,總結

來源:互聯網
上載者:User

標籤:des   style   class   blog   code   java   

XPath簡介

XPath是W3C的一個標準。它最主要的目的是為了在XML1.0或XML1.1文檔節點樹中定位節點所設計。目前有XPath1.0和XPath2.0兩個版本。其中Xpath1.0是1999年成為W3C標準,而XPath2.0標準的確立是在2007年。W3C關於XPath的英文詳細文檔請見:http://www.w3.org/TR/xpath20/ 。

XPath是一種運算式語言,它的傳回值可能是節點,節點集合,原子值,以及節點和原子值的混合等。XPath2.0是XPath1.0的超集。它是對XPath1.0的擴充,它可以支援更加豐富的資料類型,並且XPath2.0保持了對XPath1.0的相對很好的向後相容性,幾乎所有的XPath2.0的返回結果都可以和XPath1.0保持一樣。另外XPath2.0也是XSLT2.0和XQuery1.0的用於查詢定位節點的主運算式語言。XQuery1.0是對XPath2.0的擴充。關於在XSLT和XQuery中使用XPath運算式定位節點的知識在後面的執行個體中會有所介紹。

在學習XPath之前你應該對XML的節點,元素,屬性,原子值(文本),處理指示,注釋,根節點(文檔節點),命名空間以及對節點間的關係如:父(Parent),子(Children),兄弟(Sibling),先輩(Ancestor),後代(Descendant)等概念有所瞭解。這裡不在說明。

XPath路徑運算式

在本小節下面的內容中你將可以學習到:

  • 路徑運算式文法
  • 相對/絕對路徑
  • 運算式上下文
  • 謂詞(篩選條件運算式)及軸的概念
  • 運算子及特殊字元
  • 常用運算式執行個體
  • 函數及說明

這裡給出一個執行個體Xml檔案。下面的說明及執行個體都是基於該XML檔案。

路徑運算式文法: 

  1. 路徑 = 相對路徑 | 絕對路徑
  2. XPath路徑運算式 = 步進運算式 | 相對路徑 "/"步進運算式。
  3. 步進運算式=軸 節點測試 謂詞

說明:

  1. 其中軸表示步進運算式選擇的節點和當前上下文節點間的樹狀關係(層次關係),節點測試指定步進運算式選擇的節點名稱副檔名,謂詞即相當於過濾運算式以進一步過濾細化節點集。
  2. 謂詞可以是0個或多個。多個多個謂詞用邏輯操作符and, or串連。取邏輯非用not()函數。
請看一個典型的XPath查詢運算式:/messages/message//child::node()[@id=0],其中/messages/message是路徑(絕對路徑以"/"開始),child::是軸表示在子節點下選擇,node()是節點測試表示選擇所有的節點。[@id=0]是謂詞,表示選擇所有有屬性id並且值為0的節點。  相對路徑與絕對路徑:如果"/"處在XPath運算式開頭則表示文檔根項目,(運算式中間作為分隔字元用以分割每一個步進運算式)如:/messages/message/subject是一種絕對路徑標記法,它表明是從文檔根開始尋找節點。假設當前節點是在第一個message節點【/messages/message[1]】,則路徑運算式subject(路徑前沒有"/")這種標記法稱為相對路徑,表明從當前節點開始尋找。具體請見下面所述的"運算式上下文"。 運算式上下文(Context):上下文其實表示一種環境。以明確當前XPath路徑運算式處在什麼樣的環境下執行。例如同樣一個路徑運算式處在對根節點操作的環境和處在對某一個特定子節點操作的環境下執行所獲得的結果可能是完全不一樣的。也就是說XPath路徑運算式計算結果取決於它所處的上下文。 XPath上下文基本有以下幾種
  • 當前節點(./): 
    如./sender表示選擇當前節點下的sender節點集合(等同於下面所講的"特定元素",如:sender)
  • 父節點(../): 
    如../sender表示選擇當前節點的父節點下的sender節點集合
  • 根項目(/): 
    如/messages表示選擇從文檔根節點下的messages節點集合.
  • 根節點(/*): 
    這裡的*是代表所有節點,但是根項目只有一個,所以這裡表示根節點。/*的返回結果和/messages返回的結果一樣都是messages節點。
  • 遞迴下降(//): 
    如當前上下文是messages節點。則//sender將返回以下結果: 
    /messages//sender : 
    <sender>[email protected]</sender> 
    <sender>[email protected]</sender> 
    <sender>[email protected]</sender> 

    /messages/message[1]//sender: 
    <sender>[email protected]</sender> 
    <sender>[email protected]</sender> 

    我們可以看出XPath運算式返回的結果是:從當前節點開始遞迴步進搜尋當前節點下的所有子節點找到滿足條件的節點集。
  • 特定元素 
    如sender:表示選擇當前節點下的sender節點集合,等同於(./sender)
注意:在執行XPath時一定要注意上下文。即當前是在哪個節點下執行XPath運算式。這在XMLDOM中很重要。如:在XMLDOM中的selectNodes,selectSingleNode方法的參數都是一個XPath運算式,此時這個XPath運算式的執行內容就是調用這個方法的節點及它所在的環境。更多資訊請參見:http://www.w3.org/TR/xpath20/ 謂詞(篩選條件運算式)及軸的概念:XPath的謂詞即篩選條件運算式,類似於SQL的where子句.

 

軸名稱 結果
ancestor 選取當前節點的所有先輩(父、祖父等)
ancestor-or-self 選取當前節點的所有先輩(父、祖父等)以及當前節點本身
attribute 選取當前節點的所有屬性
child 選取當前節點的所有子項目。
descendant 選取當前節點的所有後代元素(子、孫等)。
descendant-or-self 選取當前節點的所有後代元素(子、孫等)以及當前節點本身。
following 選取文檔中當前節點的結束標籤之後的所有節點。
namespace 選取當前節點的所有命名空間節點
parent 選取當前節點的父節點。
preceding 直到所有這個節點的父輩節點,順序選擇每個父輩節點前的所有同級節點
preceding-sibling 選取當前節點之前的所有同級節點。
self 選取當前節點。

 

運算子及特殊字元:

 

運算子/特殊字元 說明
/ 此路徑運算子出現在模式開頭時,表示應從根節點選擇。
// 從當前節點開始遞迴下降,此路徑運算子出現在模式開頭時,表示應從根節點遞迴下降。
. 當前上下文。
.. 當前上下文節點父級。
* 萬用字元;選擇所有元素節點與元素名無關。(不包括文本,注釋,指令等節點,如果也要包含這些節點請用node()函數)
@ 屬性名稱的首碼。
@* 選擇所有屬性,與名稱無關。
: 命名空間分隔字元;將命名空間首碼與元素名或屬性名稱分隔。
( ) 括弧運算子(優先順序最高),強制運算優先順序。
[ ] 應用篩選模式(即謂詞,包括"過濾運算式"和"軸(向前/向後)")。
[ ] 下標運算子;用於在集合中編製索引。
| 兩個節點集合的聯合,如://messages/message/to | //messages/message/cc
- 減法。
div, 浮點除法。
and, or 邏輯運算。
mod 求餘。
not() 邏輯非
= 等於
!= 不等於
特殊比較子 < 或者 &lt;<= 或者 &lt;=> 或者 &gt;>= 或者 &gt;=需要轉義的時候必須使用轉義的形式,如在XSLT中,而在XMLDOM的scripting中不需要轉義。

 

常用運算式執行個體:

 

/ Document Root文檔根.
/* 選擇文檔根下面的所有元素節點,即根節點(XML文檔只有一個根節點)
/node() 根項目下所有的節點(包括文本節點,注釋節點等)
/text() 尋找文檔根節點下的所有文本節點
/messages/message messages節點下的所有message節點
/messages/message[1] messages節點下的第一個message節點
/messages/message[1]/self::node() 第一個message節點(self軸表示自身,node()表示選擇所有節點)
/messages/message[1]/node() 第一個message節點下的所有子節點
/messages/message[1]/*[last()] 第一個message節點的最後一個子節點
/messages/message[1]/[last()] Error,謂詞前必須是節點或節點集
/messages/message[1]/node()[last()] 第一個message節點的最後一個子節點
/messages/message[1]/text() 第一個message節點的所有子節點
/messages/message[1]//text() 第一個message節點下遞迴下降尋找所有的文本節點(無限深度)
/messages/message[1] /child::node()/messages/message[1] /node()/messages/message[position()=1]/node()//message[@id=1] /node() 第一個message節點下的所有子節點
//message[@id=1] //child::node() 遞迴所有子節點(無限深度)
//message[position()=1]/node() 選擇id=1的message節點以及id=0的message節點
/messages/message[1] /parent::* Messages節點
/messages/message[1]/body/attachments/parent::node()/messages/message[1]/body/attachments/parent::* /messages/message[1]/body/attachments/.. attachments節點的父節點。父節點只有一個,所以node()和* 返回結果一樣。(..也表示父節點. 表示自身節點)
//message[@id=0]/ancestor::* Ancestor軸表示所有的祖輩,父,祖父等。向上遞迴
//message[@id=0]/ancestor-or-self::* 向上遞迴,包含自身
//message[@id=0]/ancestor::node() 對比使用*,多一個文檔根項目(Document root)
/messages/message[1]/descendant::node()//messages/message[1]//node() 遞迴下降尋找message節點的所有節點
/messages/message[1]/sender/following::* 尋找第一個message節點的sender節點後的所有同級節點,並對每一個同級節點遞迴向下尋找。
//message[@id=1]/sender/following-sibling::* 尋找id=1的message節點的sender節點的所有後續的同級節點。
//message[@id=1]/datetime/@date 尋找id=1的message節點的datetime節點的date屬性
//message[@id=1]/datetime[@date]//message/datetime[attribute::date] 尋找id=1的message節點的所有含有date屬性的datetime節點
//message[datetime] 尋找所有含有datetime節點的message節點
//message/datetime/attribute::*//message/datetime/attribute::node()//message/datetime/@* 返回message節點下datetime節點的所有屬性節點
//message/datetime[attribute::*]//message/datetime[attribute::node()]//message/datetime[@*]//message/datetime[@node()] 選擇所有含有屬性的datetime節點
//attribute::* 選擇根節點下的所有屬性節點
//message[@id=0]/body/preceding::node() 順序選擇body節點所在節點前的所有同級節點。(尋找順序為:先找到body節點的頂級節點(根節點),得到根節點標籤前的所有同級節點,執行完成後繼續向下一級,順序得到該節點標籤前的所有同級節點,依次類推。)注意:尋找同級節點是順序尋找,而不是遞迴尋找。
//message[@id=0]/body/preceding-sibling::node() 順序尋找body標籤前的所有同級節點。(和上例一個最大的區別是:不從最頂層開始到body節點逐層尋找。我們可以理解成少了一個迴圈,而只尋找當前節點前的同級節點)
//message[@id=1]//*[namespace::amazon] 尋找id=1的所有message節點下的所有命名空間為amazon的節點。
//namespace::* 文檔中的所有的命名空間節點。(包括預設命名空間xmlns:xml)
//message[@id=0]//books/*[local-name()=‘book‘] 選擇books下的所有的book節點,注意:由於book節點定義了命名空間<amazone:book>.若寫成//message[@id=0]//books/book則尋找不出任何節點。
//message[@id=0]//books/*[local-name()=‘book‘ and namespace-uri()=‘http://www.amazon.com/books/schema‘] 選擇books下的所有的book節點,(節點名和命名空間都匹配)
//message[@id=0]//books/*[local-name()=‘book‘][year>2006] 選擇year節點值>2006的book節點
//message[@id=0]//books/*[local-name()=‘book‘][1]/year>2006 指示第一個book節點的year節點值是否大於2006.返回xs:boolean: true

 

函數及說明: 值得欣喜的是XPath函數和XSLT,XQuery等共用函數庫,函數庫為我們提供了功能豐富的各種函數的調用,我們也可以自訂自己的函數。這裡不再對每個函數的用法逐一說明,英文好點的朋友直接去看看w3關於XPath函數的介紹吧:http://www.w3.org/TR/xquery-operators 。中文的可以參考這個網站, http://www.w3school.com.cn/xpath/xpath_functions.asp  XPath在DOM,XSLT及XQuery中的應用

 

 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml"> 
<head> 
<title>XPath Test</title> 
</head> 
<body> 

<script language="javascript" type="text/javascript"> 
var xmlDoc = new ActiveXObject("Microsoft.XMLDOM"); 
xmlDoc.async="false"; 
xmlDoc.load("messages.xml"); 
xmlDoc.setProperty("SelectionLanguage", "XPath"); 
    var sPath = "/messages/message[1]//books/*[local-name()=‘book‘]"; 
var bookNodes = xmlDoc.selectNodes(sPath); 

document.write("<ul>"); 
for ( var i = 0; i < bookNodes.length; i++) { 
document.write("<li>" + bookNodes[i].childNodes[0].text + "</li>"); 

document.write("</ul>"); 
</script> 

</body> 
</html>

 

注意:我們若使用new ActiveXObject("Microsoft.XMLDOM")則需要注意的是:因為早期的XMLDOM的SelectionLanguage屬性預設是Regex,不是XPath語言。所以需要指定這樣一條語句xmlDoc.setProperty("SelectionLanguage", "XPath"); 以支援XPath查詢運算式。.若沒有指定SelectionLanguage屬性值為XPath則要注意以下情況:
  1. 數組下標從0開始(我們知道在XPath查詢運算式中數組下標是從1開始的)
  2. 不支援在XPath查詢運算式中使用XPath函數。
XSLT: 
見:我的另外一篇關於如何使用XSLT的一個小示範http://www.cnblogs.com/ktgu/archive/2008/12/14/1354890.html XQuery: 

 

xquery version "1.0"; 

<ul> 

let $i := 0 
for $x in doc("C:\Users\Administrator\Desktop\messages.xml")//message[@id=0]//books/*[local-name()=‘book‘] 
where $x/year>2006 
order by $x/year descending 
return <li>{ data($x/name) } </li> 

</ul>

 

返回結果<ul> 
    <li>Microsoft Visual C# 2008 Step by Step </li> 
    <li>Professional C# 2008 </li> 
</ul>

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.