二十七、XPath
二十七、XPath
XPath是一種節點查找手段,對比之前使用標準DOM去查找XML中的節點方式,大大降低了查找難度,方便開發者使用。但是,DOM3級以前的標準並沒有就XPath做出規範;直到DOM3在首次推薦到標準規範行列。大部分瀏覽器實現了這個標準,IE則以自己的方式實現了XPath。
1.IE中的XPath
在IE8及之前的瀏覽器,XPath是采用內置基於ActiveX的XML DOM文檔對象實現的。在每一個節點上提供了兩個方法:selectSingleNode()和selectNodes()。
selectSingleNode()方法接受一個XPath模式(也就是查找路徑),找到匹配的第一個節點並將它返回,沒有則返回null。
var user = xmlDom.selectSingleNode(‘root/user‘); //得到第一個user節點
alert(user.xml); //查看xml序列
alert(user.tagName); //節點元素名
alert(user.firstChild.nodeValue); //節點內的值
上下文節點:
//通過xmlDom,並且使用root/user的路徑
var user = xmlDom.selectSingleNode(‘root/user‘);
alert(user.tagName); //user
//通過xmlDom.documentElement,並且使用user路徑,省去了root
var user = xmlDom.documentElement.selectSingleNode(‘user‘);
alert(user.tagName); //user
//通過xmlDom,並且使用user路徑,省去了root
var user = xmlDom.selectSingleNode(‘user‘);
alert(user.tagName); //找不到了,出錯
PS:xmlDom和xmlDom.documentElement都是上下文節點,主要就是定位當前路徑查找的指針,而xmlDom對象實例的指針就是在最根上。
XPath常用語法
//通過user[n]來獲取第n+1條節點,PS:XPath其實是按1為起始值的
var user = xmlDom.selectSingleNode(‘root/user[1]‘);
alert(user.xml);
//通過text()獲取節點內的值
var user = xmlDom.selectSingleNode(‘root/user/text()‘);
alert(user.xml);
alert(user.nodeValue);
//通過//user表示在整個xml獲取到user節點,不關心任何層次
var user = xmlDom.selectSingleNode(‘//user‘);
alert(user.xml);
//通過root//user表示在root包含的層次下獲取到user節點,在root內不關心任何層次
var user = xmlDom.selectSingleNode(‘root//user‘);
alert(user.tagName);
//通過root/user[@id=6]表示獲取user中id=6的節點
var user = xmlDom.selectSingleNode(‘root/user[@id=6]‘);
alert(user.xml);
PS:更多的XPath語法,可以參考XPath手冊或者XML DOM手冊進行參考,這裏只提供了最常用的語法。
selectSingleNode()方法是獲取單一節點,而selectNodes()方法則是獲取一個節點集合。
var users = xmlDom.selectNodes(‘root/user‘); //獲取user節點集合
alert(users.length);
alert(users[1].xml);
2.W3C下的XPath
在DOM3級XPath規範定義的類型中,最重要的兩個類型是XPathEvaluator和XPathResult。其中,XPathEvaluator用於在特定上下文對XPath表達式求值。
XPathEvaluator的方法
方法 |
說明 |
createExpression(e, n) |
將XPath表達式及命名空間轉化成XPathExpression |
createNSResolver(n) |
根據n命名空間創建一個新的XPathNSResolver對象 |
evaluate(e, c, n ,t ,r) |
結合上下文來獲取XPath表達式的值 |
W3C實現XPath查詢節點比IE來的復雜,首先第一步就是需要得到XPathResult對象的實例。得到這個對象實例有兩種方法,一種是通過創建XPathEvaluator對象執行evaluate()方法,另一種是直接通過上下文節點對象(比如xmlDom)來執行evaluate()方法。
//使用XPathEvaluator對象創建XPathResult
var eva = new XPathEvaluator();
var result = eva.evaluate(‘root/user‘, xmlDom, null,
XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
alert(result);
//使用上下文節點對象(xmlDom)創建XPathResult
var result = xmlDom.evaluate(‘root/user‘, xmlDom, null,
XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
alert(result);
相對而言,第二種簡單方便一點,但evaluate方法有五個屬性:1.XPath路徑、2.上下文節點對象、3.命名空間求解器(通常是null)、4.返回結果類型、5保存結果的XPathResult對象(通常是null)。
對於返回的結果類型,有10中不同的類型
常量 |
說明 |
XPathResult.ANY_TYPE |
返回符合XPath表達式類型的數據 |
XPathResult.ANY_UNORDERED_NODE_TYPE |
返回匹配節點的節點集合,但順序可能與文檔中的節點的順序不匹配 |
XPathResult.BOOLEAN_TYPE |
返回布爾值 |
XPathResult.FIRST_ORDERED_NODE_TYPE |
返回只包含一個節點的節點集合,且這個節點是在文檔中第一個匹配的節點 |
XPathResult.NUMBER_TYPE |
返回數字值 |
XPathResult.ORDERED_NODE_ITERATOR_TYPE |
返回匹配節點的節點集合,順序為節點在文檔中出現的順序。這是最常用到的結果類型 |
XPathResult.ORDERED_NODE_SNAPSHOT_TYPE |
返回節點集合快照,在文檔外捕獲節點,這樣將來對文檔的任何修改都不會影響這個節點列表 |
XPathResult.STRING_TYPE |
返回字符串值 |
XPathResult.UNORDERED_NODE_ITERATOR_TYPE |
返回匹配節點的節點集合,不過順序可能不會按照節點在文檔中出現的順序排列 |
XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE |
返回節點集合快照,在文檔外捕獲節點,這樣將來對文檔的任何修改都不會影響這個節點列表 |
PS:上面的常量過於繁重,對於我們只需要學習了解,其實也就需要兩個:1.獲取一個單一節、2.獲取一個節點集合。
1.獲取一個單一節點
var result = xmlDom.evaluate(‘root/user‘, xmlDom, null,
XPathResult.FIRST_ORDERED_NODE_TYPE, null);
if (result !== null) {
alert(result.singleNodeValue.tagName); //singleNodeValue屬性得到節點對象
}
2.獲取節點集合
var result = xmlDom.evaluate(‘root/user‘, xmlDom, null,
XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
var nodes = [];
if (result !== null) {
while ((node = result.iterateNext()) !== null) {
nodes.push(node);
}
}
PS:節點集合的獲取方式,是通過叠代器遍歷而來的,我們保存到數據中就模擬出IE相似的風格。
3.XPath跨瀏覽器兼容
如果要做W3C和IE的跨瀏覽器兼容,我們要思考幾個問題:1.如果傳遞一個節點的下標,IE是從0開始計算,W3C從1開始計算,可以通過傳遞獲取下標進行增1減1的操作來進行。2.獨有的功能放棄,為了保證跨瀏覽器。3.只獲取單一節點和節點列表即可,基本可以完成所有的操作。
//跨瀏覽器獲取單一節點
function selectSingleNode(xmlDom, xpath) {
var node = null;
if (typeof xmlDom.evaluate != ‘undefined‘) {
var patten = /\[(\d+)\]/g;
var flag = xpath.match(patten);
var num = 0;
if (flag !== null) {
num = parseInt(RegExp.$1) + 1;
xpath = xpath.replace(patten, ‘[‘ + num + ‘]‘);
}
var result = xmlDom.evaluate(xpath, xmlDom, null,
XPathResult.FIRST_ORDERED_NODE_TYPE, null);
if (result !== null) {
node = result.singleNodeValue;
}
} else if (typeof xmlDom.selectSingleNode != ‘undefined‘) {
node = xmlDom.selectSingleNode(xpath);
}
return node;
}
//跨瀏覽器獲取節點集合
function selectNodes(xmlDom, xpath) {
var nodes = [];
if (typeof xmlDom.evaluate != ‘undefined‘) {
var patten = /\[(\d+)\]/g;
var flag = xpath.match(patten);
var num = 0;
if (flag !== null) {
num = parseInt(RegExp.$1) + 1;
xpath = xpath.replace(patten, ‘[‘ + num + ‘]‘);
}
var node = null;
var result = xmlDom.evaluate(‘root/user‘, xmlDom, null,
XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
if (result !== null) {
while ((node = result.iterateNext()) !== null) {
nodes.push(node);
}
}
} else if (typeof xmlDom.selectNodes != ‘undefined‘) {
nodes = xmlDom.selectNodes(xpath);
}
return nodes;
}
PS:在傳遞xpath路徑時,沒有做驗證判斷是否合法,有興趣的同學可以自行完成。在XML還有一個重要章節是XSLT和EX4,由於在使用頻率的緣故,我們暫且擱置。
二十七、XPath