XPath 是一門在 XML 文檔中查找信息的語言。XPath 可用來在 XML 文檔中對元素和屬性進(jìn)行遍歷。XPath 是 W3C XSLT 標(biāo)準(zhǔn)的主要元素,并且 XQuery 和 XPointer 同時(shí)被構(gòu)建于 XPath 表達(dá)之上。因此,對 XPath 的理解是很多高級 XML 應(yīng)用的基礎(chǔ)。 其實(shí)對些我們并不陌生,最與XPath相似的便是CSS的選擇器.在CSS中使用CSS選擇符選擇元素來應(yīng)用樣式,而在XSLT中則使用XPath,XPath與CSS選擇器相比如強(qiáng)大的許多!下面是CSS選擇符與XPath選擇符一些對照:
//CSS選擇符 body p //選擇所有body下面的p元素 body>p //選擇body的子元素p * //選擇所有的元素 //與之對應(yīng)的XPath選擇符 body//p body/p *
雖然現(xiàn)在還不能了解這些XPath表達(dá)的含意,但可以發(fā)現(xiàn),它和CSS選擇符十分相像!但XPath有更強(qiáng)大的地方,比如它可以定位到body元素下具體位置上的p或可以選擇前N個(gè)p:
body/p[position()=4] //這個(gè)XPath表達(dá)式將選取body子元素中第4個(gè)p元素,注意這里從1開始計(jì)數(shù) body/p[position()<3] //將選取body子元素中前兩個(gè)p元素
XPath 使用路徑表達(dá)式來選取 XML 文檔中的節(jié)點(diǎn)或者節(jié)點(diǎn)集。這些路徑表達(dá)式和我們在常規(guī)的電腦文件系統(tǒng)中看到的表達(dá)式非常相似。另外,XPath 含有超過 100 個(gè)內(nèi)建的函數(shù)。這些函數(shù)用于字符串值、數(shù)值,日期和時(shí)間比較、節(jié)點(diǎn)和 QName 處理、序列處理、邏輯值等等。
XPath使用路徑表達(dá)式在 XML 文檔中選取節(jié)點(diǎn)。節(jié)點(diǎn)是通過沿著路徑(path)或者 步(step) 來選取的。如"/"表示文檔節(jié)點(diǎn),"."表示當(dāng)前節(jié)點(diǎn),而".."則表示當(dāng)前節(jié)點(diǎn)的父節(jié)點(diǎn).示例:
{因?yàn)閄Path表示達(dá)式中有斜杠,所以暫時(shí)用這個(gè)表示注釋! / {選取文檔節(jié)點(diǎn),nodeType為9 /root {選取文檔根元素,類似于文件系統(tǒng)的路徑(Unix),以/開頭的路徑都是絕對路徑 /root/child/.. {選取根節(jié)點(diǎn)root的子節(jié)點(diǎn)child的父節(jié)點(diǎn)(就是root)
下面是一些常用路徑表達(dá)式
<?xml version="1.0"?> <root> <child attr="attr" /> <child> <a><desc /></a> </child> </root> {針對上面的XML文檔的XPath結(jié)果,當(dāng)前節(jié)點(diǎn)為document /root {選取root root {選取root child {空,因?yàn)閏hild不是document的子元素 //child {選取兩個(gè)child元素,//表示后代 //@attr {選取attr屬性節(jié)點(diǎn) /root/child//desc {返回child的后代元素desc
謂語用于在查找節(jié)點(diǎn)時(shí)提供更詳盡的信息,謂語被嵌在方括號中。下面是一些帶有謂語的XPath表達(dá)式:
/root/child[3] {選取root元素的第三個(gè)child子元素,注意,這和數(shù)組下標(biāo)不一樣,從1開始計(jì)數(shù) //child[@attr] {選取所有具有屬性attr的child元素 //child[@attr="val"]/desc {選取所有屬性attr的值為val的child元素的子元素desc //child[desc] {選取所有的有desc子元素的child //child[position()>3] {position()是XPath中的一個(gè)函數(shù),表示節(jié)點(diǎn)的位置 //child[@attr>12] {XPath表達(dá)式還可以進(jìn)行數(shù)值比較,該表達(dá)式將選取attr屬性值大于12的child元素 //child[last()] {last()函數(shù)返回節(jié)點(diǎn)列表最后的位置,該表達(dá)式將選取最后一個(gè)child元素
XPath 通配符可用來選取未知的 XML 元素。
/root/* {選取根元素下面的所有子元素 /root/node() {選取根元素下面的所有節(jié)點(diǎn),包括文本節(jié)點(diǎn) //* {選取文檔中所有元素 //child[@*] {選取所有具有屬性的child元素 //@* {選取所有的屬性節(jié)點(diǎn)
與CSS中使用逗號組合使用多個(gè)選擇符一樣,XPath支持一種使用"|"來組合多個(gè)路徑的語法!
/root | /root/child {選取根元素root與它下面的子元素child //child | //desc {選取所有的child元素與desc元素
下面列出了可用在 XPath 表達(dá)式中的運(yùn)算符:
軸可定義某個(gè)相對于當(dāng)前節(jié)點(diǎn)的節(jié)點(diǎn)集。下面一可用的軸名稱與對應(yīng)的結(jié)果:
事實(shí)上,一個(gè)完整的XPath表達(dá)式由"/"與"步"構(gòu)成的,而步又是由 "軸" 、 "節(jié)點(diǎn)測試"和"謂語"構(gòu)成的.如下:
step/step/..... {一個(gè)XPath表達(dá)式 {step的構(gòu)成 軸名稱::節(jié)點(diǎn)測試[謂語]
在一般的XPath表達(dá)式中,沒有謂語即表達(dá)沒有其它條件限制,而沒有軸名稱,則默認(rèn)使用child.如"abc"與"child::abc"是等效的, 下面是一些與使用軸名稱等效的簡單XPath表達(dá)式:
XPath還包含一套函數(shù)庫,如position與last就是函數(shù),一般的函數(shù)被用在謂語中,而在XSLT及XQuery中它們則得到了更廣泛的使用.
IE瀏覽器對XPath的實(shí)現(xiàn)比較簡單.一個(gè)XML DOM對象(及每個(gè)節(jié)點(diǎn))都有selectSingleNode與selectNodes方法,傳入XPath表達(dá)式,selectNodes返回匹配的節(jié)點(diǎn)列表,而selectSingleNode則只返回列表中第一個(gè)項(xiàng)目!
var xmlDom = getXMLDOM();//我們之前寫的跨瀏覽器的XML DOM加載函數(shù) loadXMLFile(xmlDom,"text.xml"); var root = xmlDom.selectSingleNode("/*");//返回文檔根元素 root = xmlDom.selectNodes("/*")[0];//同上 var lastChild = xmlDom.selectSingleNode("/*/*[last()]");
Mozilla是根據(jù)DOM標(biāo)準(zhǔn)來實(shí)現(xiàn)對XPath的支持的。DOM Level 3附加標(biāo)準(zhǔn)DOM Level 3 XPath定義了用于在DOM中計(jì)算XPath表達(dá)式的接口。遺憾的是,這個(gè)標(biāo)準(zhǔn)要比微軟直觀的方式復(fù)雜得多。
雖然有好多與XPath相關(guān)的對象,最重要的兩個(gè)是:XPathEvaluator和XPathResult。XPathEvaluator利用方法evaluate()計(jì)算XPath表達(dá)式。
evaluate()方法有五個(gè)參數(shù):XPath表達(dá)式、上下文節(jié)點(diǎn)、命名空間解釋程序和返回的結(jié)果的類型,同時(shí),在XPathResult中存放結(jié)果(通常為null)。
命名空間解釋程序,只有在XML代碼用到了XML命名空間時(shí)才是必要的,所以通常留空,置為null。返回結(jié)果的類型,可以是以下十個(gè)常量值之一:
下面是使用ORDERED_NODE_ITERATOR_TYPE的例子:
var xmlDom = getXMLDOM();//我們之前寫的跨瀏覽器的XML DOM加載函數(shù) loadXMLFile(xmlDom,"text.xml"); var evaluator = new XPathEvaluator(); var result =evaluator.evaluate("/root",xmlDom,null,XPathResult.ORDERED_NODE_ITERATOR_TYPE,null); var node; if (result) {//執(zhí)行失敗會返回null while(node=result.iterateNext()) {//這個(gè)列表必須使用iterateNext方法遍歷 alert(node.tagName); } }