XML學習筆記6——XPath語言


  在上一篇筆記的結尾,我們接觸到了兩個用於選擇XML文檔中特定范圍的元素<selector>和<field>,這兩個元素的取值都是XPath表達式,那么,什么是XPath呢?簡單的說,XPath是用於在XML文檔中查找信息的語言,可用來在XML文檔中遍歷元素和屬性,很多XML的相關技術比如XSLT、XQuery、XPointer等都是構建於XPath的基礎之上,在這一篇筆記中,就來學習一下XPath語言。

1、相關術語

(1)節點(Node):格式良好的XML文檔都可以轉換為一個樹型結構,XPath中的節點也就是這個樹型結構中的節點。概況起來,有如下所列的七種節點:

節點類型 說明
XML文檔根節點 XML文檔的根稱為文檔節點或根節點
元素節點 一個元素的開始標簽、結束標簽,以及之間的全部內容整體稱之為元素節點
屬性節點 元素的每個屬性都構成一個屬性節點,包括屬性名稱和屬性值兩個部分,屬性節點必須依附於元素節點
命名空間節點 XML文檔中的xmlns:prefix屬性稱之為命名空間節點,注意和屬性節點的區別
文本節點 XML元素中間的字符數據,包括CDATA段中的字符數據
注釋節點 XML文檔里<!--和-->包含的注釋部分構成注釋節點
處理指令節點 XML文檔的處理指令部分構成處理指令節點

(2)基本值(也稱為原子值,Atomic Value):專門用於表示簡單的字面值,如整數值,字符串等。基本值可以當成沒有父節點也沒有子節點的節點。

(3)項目(Item):一個項目代表一個基本值或一個節點。

(4)節點集和序列(Sequence):XPath表達式可以表示多個節點,多個節點的組合在XPath1.0中稱為節點集,而在XPath2.0中添加了一個序列的術語,即可以代表普通的項目,也可以代表節點集。

(5)節點關系:

節點關系 說明
父節點Parent 每個元素或屬性都有一個父節點
子節點Children 元素節點可以有0個、1個或多個子節點
兄弟節點Sibling 父節點相同的節點稱之為兄弟節點
祖先節點Ancestor 節點的父節點、父節點的父節點一直到根節點
后代節點Descendant 節點的子節點,子節點的子節點......

(6)相對路徑和絕對路徑:與操作系統中的路徑類似,XPath中也有相對路徑和絕對路徑,絕對路徑以斜線(/)開頭,總是從根節點開始匹配,而相對路徑則不會以斜線開頭,從當前路徑開始匹配。

2、XPath語法

  XPath使用路徑表達式來訪問XML中的節點或節點集,每個XPath表達式總是由一個或多個步(step)組成的,多個步直接使用斜線分隔。在XPath中,步的語法格式如下:

::節點測試[限定謂語]

也就是說,每個步都通過了3次篩選,第一次是使用“”選擇節點方向,第二次使用“節點測試”選取在指定軸方向上的部分節點,第三次則是使用“限定謂語”來對選中的節點進一步過濾。

(1)軸:在XPath中,有下面列表中的各種軸:

簡化寫法 說明
ancestor   選取當前節點的所有先輩(父、祖父等)節點
ancestor-or-self   選取當前節點的所有先輩(父、祖父等)節點以及當前節點本身
attribute 選取當前節點的所有屬性節點,如果當前節點不是元素節點,則attribute軸方向上的節點集為空
child 省略不寫  選取當前節點的所有子節點
descendant //  選取當前節點的所有后代節點(子、孫等)
descendant-or-self   選取當前節點的所有后代節點(子、孫等)以及當前節點本身
following   選取文檔中當前節點的結束標簽之后的所有節點,不會包含當前節點的后代節點和屬性節點
following-sibling   選取文檔中當前節點的結束標簽之后的所有兄弟節點
namespace   選取當前節點的所有命名空間節點,當前節點不是元素節點,則namespace軸方向上的節點集為空
parent .. 選取當前節點的父節點
preceding   選取文檔中當前節點的開始標簽之前的所有節點,不會包含當前節點的后代節點和屬性節點
preceding-sibling   選取文檔中當前節點的開始標簽之前的所有兄弟節點
self . 選取當前節點

(2)節點測試:節點測試用於從指定軸方向上選取所匹配的特定的節點,在XPath中,常用的節點測試語法如下表所示:

節點測試 說明
nodename

從指定軸方向上選出具有nodename的節點

如child::book選擇當前節點的所有book子節點

   descendant::book選擇當前節點的所有book后代節點(包括book子節點、孫子節點等)

node() 選擇指定軸匹配的所有類型的節點
text()

選擇指定軸匹配的所有文本類型的節點

如child::text()選擇當前節點的所有文本子節點

  descendant::text()選擇當前節點的所有文本后代節點(包括文本子節點、文本孫子節點等)

comment() 選擇指定軸匹配的所有注釋節點
processing-instruction 選擇指定軸匹配的所有處理指令節點
* 節點測試中的通配符,表示所有,也即不進行過濾

(3)限定謂語:每個步中可以接受0個或多個限定謂語,用於進一步過濾所選取的節點集,限定謂語放在方括號中,通常限定謂語返回一個boolean值。看下面的一些例子:

路徑表達式 結果
/bookstore/book[1] 選取屬於 bookstore  元素的子元素的第一個 book 元素。
/bookstore/book[last()] 選取屬於 bookstore  元素的子元素的最后一個 book 元素。
/bookstore/book[last()-1] 選取屬於 bookstore  元素的子元素的倒數第二個 book 元素。
/bookstore/book[position()<3] 選取最前面的兩個屬於 bookstore 元素的子元素的 book 元素。
//title[@lang] 選取所有擁有名為 lang 的屬性的 title 元素。
//title[@lang='eng'] 選取所有 title 元素,且這些元素擁有值為 eng 的 lang 屬性。
/bookstore/book[price>35.00] 選取 bookstore 元素的所有 book 元素,且其中的 price 元素的值須大於 35.00。
/bookstore/book[price>35.00]/title 選取 bookstore 元素中的 book 元素的所有 title 元素,且其中的 price 元素的值須大於 35.00。

3、運算符

  從上面的實例中可以看到,在限定謂語中,還可以使用運算符、表達式,還有很多內置的函數供使用。這一小節先看看XPath中支持的運算符:

(1)算術運算符:加(+)、減(-)、乘(*)、除(div)、取模(mod)

  算術運算符非常簡單,但是需要注意幾點:

A、因為減號實際上也就是中划線,而中划線在XML中是合法的標識符號,從而帶來了歧義,於是XPath強制規定,使用減號的時候,需要前后各加一個空格。

B、在XPath中,所有的數值都是64位的double類型,即便直接書寫成0、100;另外,XPath還有幾個特殊的數值:正無窮大、負無窮大、非數。

C、在運算時,如果操作數不是數值類型,會自動轉換,下面的比較運算符、邏輯運算符如果有必要也會發生相應的自動類型轉換。

(2)比較運算符:等於(=)、不等於(!=)、小於(<)、小於或等於(<=)、大於(>)、大於或等於(>=)

  需要注意的是,不像其它編程語言,這里表示相等只需要一個等於號。

(3)邏輯運算符:與(and)、或(or)

(4)集合運算符:並集(|)

4、表達式

(1)for表達式:用於循環訪問序列中的每個項,並對每項進行一次計算,最后將每項計算得到的結果組合成序列后返回,語法格式如下:

for $var in sequence return rtExpression

實際上,這里的for更類似於js中的foreach。還可以使用下面的形式遍歷多個序列:

for $var1 in sequence1, $var2 in sequence2 return fn($var1,$var2)

(2)if表達式:用於處理分支,根據不同條件得到不同的返回值,語法格式如下:

if (condition1)
then rtVal1
[else if (condition2)
then rtVal2
...]
else
otherVal

(3)some表達式:迭代中只要有一項滿足條件就返回true,否則返回false,語法格式如下:

some $var in sequence satisfies condition

(4)every表達式:迭代中只有有一項不滿足條件就返回false,否則返回true,語法格式如下:

every $var in sequence satisfies condition

5、內置函數庫

  在XPath中還有大量的內置函數,用於增強相關功能,這些內置函數可以參考:XPath函數。我在下面也抄錄一份供參考:

分類 函數 說明
存取函數 fn:node-name(node) 返回參數節點的節點名稱。
fn:nilled(node) 返回是否拒絕參數節點的布爾值。
fn:data(item.item,...) 接受項目序列,並返回原子值序列。
  • fn:base-uri()
  • fn:base-uri(node)
返回當前節點或指定節點的 base-uri 屬性的值。
  • fn:document-uri()
  • fn:document-uri(node)
返回當前節點或指定節點的 document-uri 屬性的值。
錯誤和跟蹤函數
  • fn:error()
  • fn:error(error)
  • fn:error(error,description)
  • fn:error(error,description,error-object)

例子:error(fn:QName('http://example.com/test', 'err:toohigh'), 'Error: Price is too high')

結果:向外部處理環境返回 http://example.com/test#toohigh 以及字符串 "Error: Price is too high"。

fn:trace(value,label) 用於對查詢進行 debug。
數值函數 fn:number(arg)

返回參數的數值。參數可以是布爾值、字符串或節點集。

例子:number('100')

結果:100

fn:abs(num) 返回參數的絕對值。
fn:ceiling(num) 返回大於或等於 num 參數的最小整數。
fn:floor(num) 返回小於或等於 num 參數的最大整數。
fn:round(num) 把 num 參數四舍五入為最接近的整數。
fn:round-half-to-even()

返回最接近參數num的偶數

例子:round-half-to-even(0.5) 結果:0

例子:round-half-to-even(1.5) 結果:2

例子:round-half-to-even(2.5) 結果:2

字符串函數 fn:string(arg) 返回參數的字符串值。參數可以是數字、邏輯值或節點集。 
fn:codepoints-to-string(int,int,...)

根據一個Unicode值序列序列返回字符串。

例子:codepoints-to-string((84, 104, 233, 114, 232, 115, 101))

結果:'Thérèse'

注意:該函數的參數是一個Unicode值序列,因此必須用括號將參數括起來

fn:string-to-codepoints(string) 根據字符串返回每個字符所對應的Unicode值的序列。
fn:codepoint-equal(comp1,comp2) 根據 Unicode 值序列比較,如果 comp1 的值等於 comp2 的值,則返回 true,否則返回 false。 
  • fn:compare(comp1,comp2)
  • fn:compare(comp1,comp2,collation)

根據對照規則,comp1小於comp2返回 -1;comp1等於comp2,返回0;comp1大於comp2返回1。

fn:concat(string,string,...) 返回字符串的拼接。
fn:string-join((string,string,...),sep) 使用 sep 參數作為分隔符,來返回 string 參數拼接后的字符串。
  • fn:substring(string,start,len)
  • fn:substring(string,start)

返回從 start 位置開始的指定長度的子字符串。第一個字符的下標是 1。

如果省略 len 參數,則返回從位置 start 到字符串末尾的子字符串。

  • fn:string-length(string)
  • fn:string-length()
返回指定字符串的長度。如果沒有 string 參數,則返回當前節點的字符串值的長度
  • fn:normalize-space(string)
  • fn:normalize-space()
刪除指定字符串的首尾空白,並把內部連續空白壓縮為一個,然后返回結果。沒有參數,則處理當前節點。 
fn:normalize-unicode() 執行 Unicode 規格化。
fn:upper-case(string)  把 string 參數轉換為大寫。
fn:lower-case(string)  把 string 參數轉換為小寫。
fn:translate(string1,string2,string3) 

把 string1 中的 string2 替換為 string3。

例子:translate('12:30','30','45')

結果:'12:45'

例子:translate('12:30','03','54')

結果:'12:45'

例子:translate('12:30','0123','abcd')

結果:'bc:da'

fn:escape-uri(stringURI,esc-res) 

例子:escape-uri("http://example.com/test#car", true())

結果:"http%3A%2F%2Fexample.com%2Ftest#car"

例子:escape-uri("http://example.com/test#car", false())

結果:http://example.com/test#car

例子:escape-uri ("http://example.com/~bébé", false())

結果:"http://example.com/~b%C3%A9b%C3%A9"

fn:contains(string1,string2)  如果 string1 包含 string2,則返回 true,否則返回 false。
fn:starts-with(string1,string2)  如果 string1 以 string2 開始,則返回 true,否則返回 false。
fn:ends-with(string1,string2)  如果 string1 以 string2 結尾,則返回 true,否則返回 false。
fn:substring-before(string1,string2)  返回 string2 在 string1 中出現之前的子字符串。
fn:substring-after(string1,string2)  返回 string2 在 string1 中出現之后的子字符串。
fn:matches(string,pattern)  如果 string 參數匹配指定的模式,則返回 true,否則返回 false。
fn:replace(string,pattern,replace)  把指定的模式替換為 replace 參數,並返回結果。
fn:tokenize(string,pattern)

例子:tokenize("XPath is fun", "\s+")

結果:("XPath", "is", "fun")

anyURI函數 fn:resolve-uri(relative,base)  
邏輯函數 fn:boolean(arg)  返回數字、字符串或節點集的布爾值。
fn:not(arg)  首先通過 boolean() 函數把參數還原為一個布爾值,然后再取反。 
fn:true()  返回布爾值 true。 
fn:false()  返回布爾值 false。 
日期時間函數 fn:dateTime(date,time)  把參數轉換為日期和時間。 
fn:years-from-duration(datetimedur) 返回參數值的年份部分的整數,以標准詞匯表示法來表示。 
fn:months-from-duration(datetimedur)  返回參數值的月份部分的整數,以標准詞匯表示法來表示。 
fn:days-from-duration(datetimedur)  返回參數值的天部分的整數,以標准詞匯表示法來表示。 
fn:hours-from-duration(datetimedur)  返回參數值的小時部分的整數,以標准詞匯表示法來表示。 
fn:minutes-from-duration(datetimedur)  返回參數值的分鍾部分的整數,以標准詞匯表示法來表示。 
fn:seconds-from-duration(datetimedur)  返回參數值的分鍾部分的十進制數,以標准詞匯表示法來表示。 
fn:year-from-dateTime(datetime)  返回參數本地值的年部分的整數。 
fn:month-from-dateTime(datetime)  返回參數本地值的月部分的整數。 
fn:day-from-dateTime(datetime)  返回參數本地值的天部分的整數。 
fn:hours-from-dateTime(datetime)  返回參數本地值的小時部分的整數。 
fn:minutes-from-dateTime(datetime)  返回參數本地值的分鍾部分的整數。 
fn:seconds-from-dateTime(datetime)  返回參數本地值的秒部分的十進制數。 
fn:timezone-from-dateTime(datetime)  返回參數的時區部分,如果存在。 
fn:year-from-date(date)  返回參數本地值中表示年的整數。 
fn:month-from-date(date)  返回參數本地值中表示月的整數。 
fn:day-from-date(date) 返回參數本地值中表示天的整數。 
fn:timezone-from-date(date)  返回參數的時區部分,如果存在。 
fn:hours-from-time(time)  返回參數本地值中表示小時部分的整數。 
fn:minutes-from-time(time) 返回參數本地值中表示分鍾部分的整數。 
fn:seconds-from-time(time)  返回參數本地值中表示秒部分的整數。 
fn:timezone-from-time(time)  返回參數的時區部分,如果存在。 
fn:adjust-dateTime-to-timezone(datetime,timezone)  如果 timezone 參數為空,則返回沒有時區的 dateTime。否則返回帶有時區的 dateTime。 
fn:adjust-date-to-timezone(date,timezone) 如果 timezone 參數為空,則返回沒有時區的 date。否則返回帶有時區的 date。 
fn:adjust-time-to-timezone(time,timezone) 如果 timezone 參數為空,則返回沒有時區的 time。否則返回帶有時區的 time。 
 QName相關函數  fn:QName()   
fn:local-name-from-QName()  
fn:namespace-uri-from-QName()   
fn:namespace-uri-for-prefix()   
fn:in-scope-prefixes()   
fn:resolve-QName()   
節點函數 
  •  
  • fn:name()
  • fn:name(nodeset)
返回當前節點的名稱或指定節點集中的第一個節點。 
  • fn:local-name()
  • fn:local-name(nodeset)
返回當前節點的名稱或指定節點集中的第一個節點 - 不帶有命名空間前綴。 
  • fn:namespace-uri()
  • fn:namespace-uri(nodeset)
返回當前節點或指定節點集中第一個節點的命名空間 URI。 
fn:lang(lang) 

如果當前節點的語言匹配指定的語言,則返回 true。

例子:Lang("en") is true for <p xml:lang="en">...</p>

例子:Lang("de") is false for <p xml:lang="en">...</p>

  • fn:root()
  • fn:root(node)
返回當前節點或指定的節點所屬的節點樹的根節點。通常是文檔節點。 
上下文函數 fn:position() 

返回當前正在被處理的節點的 index 位置。

例子://book[position()<=3]

結果:選擇前三個 book 元素

fn:last() 

返回在被處理的節點列表中的項目數目。

例子://book[last()]

結果:選擇最后一個 book 元素 

fn:current-dateTime()  返回當前的 dateTime(帶有時區)。 
fn:current-date()  返回當前的日期(帶有時區)。 
fn:current-time()  返回當前的時間(帶有時區)。 
fn:implicit-timezone()  返回隱式時區的值。 
fn:default-collation()  返回默認對照的值。
fn:static-base-uri()  返回 base-uri 的值。 
序列函數 一般序列函數 fn:index-of((item,item,...),searchitem) 

返回在項目序列中等於 searchitem 參數的位置。

例子:index-of ((15, 40, 25, 40, 10), 40)

結果:(2, 4)

fn:remove((item,item,...),position)  返回由 item 參數構造的新序列 - 同時刪除 position 參數指定的項目。 
fn:empty(item,item,...)  如果參數值是空序列,則返回 true,否則返回 false。 
fn:exists(item,item,...)  如果參數值不是空序列,則返回 true,否則返回 false。 
fn:distinct-values((item,item,...),collation) 

返回唯一不同的值。

例子:distinct-values((1, 2, 3, 1, 2))

結果:(1, 2, 3) 

fn:insert-before((item,item,...),pos,inserts)  返回由 item 參數構造的新序列 - 同時在 pos 參數指定位置插入 inserts 參數的值。 
fn:reverse((item,item,...))  返回指定的項目的顛倒順序。 
fn:subsequence((item,item,...),start,len)  返回 start 參數指定的位置返回項目序列,序列的長度由 len 參數指定。第一個項目的位置是 1。 
fn:unordered((item,item,...)) 依據實現決定的順序來返回項目。 
容量測試函數 fn:zero-or-one(item,item,...)  如果參數包含零個或一個項目,則返回參數,否則生成錯誤。 
fn:one-or-more(item,item,...)  如果參數包含一個或多個項目,則返回參數,否則生成錯誤。 
fn:exactly-one(item,item,...)  如果參數包含一個項目,則返回參數,否則生成錯誤。 
比較函數 fn:deep-equal(param1,param2,collation) 如果 param1 和 param2 與彼此相等(deep-equal),則返回 true,否則返回 false。
合計函數 fn:count((item,item,...))  返回節點的數量。 
fn:avg((arg,arg,...)) 返回參數值的平均數。
fn:max((arg,arg,...)) 返回參數中的最大值。
fn:min((arg,arg,...)) 返回參數中的最小值。
fn:sum(arg,arg,...) 返回指定節點集中每個節點的數值的總和。
序列生成函數 fn:id((string,string,...),node)  
fn:idref((string,string,...),node)  
fn:data((item1,item2,...)) 返回item1、item2等各項的值所組成的序列。
fn:doc(URI)  
fn:doc-available(URI) 如果 doc() 函數返回文檔節點,則返回 true,否則返回 false。
  • fn:collection()
  • fn:collection(string)
 

很明顯,把這些內置函數放在這里的目的並不是要強行記住,而只是需要的時候當字典查查(XQuery1.0和XPath共享了這些內置函數,有事沒事看看,混個眼熟也挺好的)。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM