在上一篇筆記的結尾,咱們接觸到了兩個用於選擇XML文檔中特定範圍的元素<selector>和<field>,這兩個元素的取值都是XPath表達式,那麼,什麼是XPath呢?簡單的說,XPath是用於在XML文檔中查找信息的語言,可用來在XML文檔中遍歷元素和屬性,不少XML的相關技術好比XSLT、XQuery、XPointer等都是構建於XPath的基礎之上,在這一篇筆記中,就來學習一下XPath語言。node
一、相關術語web
(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中也有相對路徑和絕對路徑,絕對路徑以斜線(/)開頭,老是從根節點開始匹配,而相對路徑則不會以斜線開頭,從當前路徑開始匹配。spa
二、XPath語法操作系統
XPath使用路徑表達式來訪問XML中的節點或節點集,每一個XPath表達式老是由一個或多個步(step)組成的,多個步直接使用斜線分隔。在XPath中,步的語法格式以下:debug
軸::節點測試[限定謂語]
也就是說,每一個步都經過了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。 |
三、運算符
從上面的實例中能夠看到,在限定謂語中,還可使用運算符、表達式,還有不少內置的函數供使用。這一小節先看看XPath中支持的運算符:
(1)算術運算符:加(+)、減(-)、乘(*)、除(div)、取模(mod)
算術運算符很是簡單,可是須要注意幾點:
A、由於減號實際上也就是中劃線,而中劃線在XML中是合法的標識符號,從而帶來了歧義,因而XPath強制規定,使用減號的時候,須要先後各加一個空格。
B、在XPath中,全部的數值都是64位的double類型,即使直接書寫成0、100;另外,XPath還有幾個特殊的數值:正無窮大、負無窮大、非數。
C、在運算時,若是操做數不是數值類型,會自動轉換,下面的比較運算符、邏輯運算符若是有必要也會發生相應的自動類型轉換。
(2)比較運算符:等於(=)、不等於(!=)、小於(<)、小於或等於(<=)、大於(>)、大於或等於(>=)
須要注意的是,不像其它編程語言,這裏表示相等只須要一個等於號。
(3)邏輯運算符:與(and)、或(or)
(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
五、內置函數庫
在XPath中還有大量的內置函數,用於加強相關功能,這些內置函數能夠參考:XPath函數。我在下面也抄錄一份供參考:
分類 | 函數 | 說明 | |
存取函數 | fn:node-name(node) | 返回參數節點的節點名稱。 | |
fn:nilled(node) | 返回是否拒絕參數節點的布爾值。 | ||
fn:data(item.item,...) | 接受項目序列,並返回原子值序列。 | ||
|
返回當前節點或指定節點的 base-uri 屬性的值。 | ||
|
返回當前節點或指定節點的 document-uri 屬性的值。 | ||
錯誤和跟蹤函數 |
|
例子: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。 | ||
|
根據對照規則,comp1小於comp2返回 -1;comp1等於comp2,返回0;comp1大於comp2返回1。 |
||
fn:concat(string,string,...) | 返回字符串的拼接。 | ||
fn:string-join((string,string,...),sep) | 使用 sep 參數做爲分隔符,來返回 string 參數拼接後的字符串。 | ||
|
返回從 start 位置開始的指定長度的子字符串。第一個字符的下標是 1。 若是省略 len 參數,則返回從位置 start 到字符串末尾的子字符串。 |
||
|
返回指定字符串的長度。若是沒有 string 參數,則返回當前節點的字符串值的長度 | ||
|
刪除指定字符串的首尾空白,並把內部連續空白壓縮爲一個,而後返回結果。沒有參數,則處理當前節點。 | ||
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() | |||
節點函數
|
|
返回當前節點的名稱或指定節點集中的第一個節點。 | |
|
返回當前節點的名稱或指定節點集中的第一個節點 - 不帶有命名空間前綴。 | ||
|
返回當前節點或指定節點集中第一個節點的命名空間 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: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,...)) | 返回item一、item2等各項的值所組成的序列。 | ||
fn:doc(URI) | |||
fn:doc-available(URI) | 若是 doc() 函數返回文檔節點,則返回 true,不然返回 false。 | ||
|
很明顯,把這些內置函數放在這裏的目的並非要強行記住,而只是須要的時候當字典查查(XQuery1.0和XPath共享了這些內置函數,有事沒事看看,混個眼熟也挺好的)。