XPath是設計用來在DOM文件中查詢節點的一種手段,因而對XML的處理也很重要。很多瀏覽器實現了這個標準,IE有自己的實現方式。
DOM3級XPath
下面的程式碼是用來檢測瀏覽器是否支援DOM3級的XPath:
var supportsXPath=document.implementation.hasFeature("XPath","3.0");
在DOM3級的XPath規範定義的型別中,最重要的兩個型別是
-
XPathEvaluator
-
XPathResult
XPathEvaluator
用在特定的上下文中對XPath表示式的求值。這個型別由三個方法:
-
createExpression(expression,nsresolver)
:將XPath表示式及相應的名稱空間資訊轉化成一個XPathExpression,這是查詢的編譯版。在多次使用同一個查詢時很有用。 -
createNSResolver(node)
:根據node的名稱空間資訊建立一個新的XPathNSResolver物件。在基於使用名稱空間的XML文件求值時,需要使用XPathNSResolver物件。 -
evaluate(expression.context,nsresolver,type,result)
:在給定的上下文中基於特定的名稱空間資訊來對XPath求值,剩下的引數指定如何返回結果。
evaluate方法最常用。這個方法接收5個引數:
-
XPath表示式
-
上下文節點
-
名稱空間求解器
-
返回結果的型別和儲存結果的XPathResult物件(通常是null,因為結果會以函式值的形式返回)。
第三個引數只在XML程式碼中使用了XML名稱空間時有必要指定,如果沒使用,設定為null。
第四個引數的的取值範圍是下列的常量之一:
-
XPathResult.ANY_TYPE
:返回與XPath表示式匹配的資料型別 -
XPathResult.NUMBER_TYPE
:數字 -
XPathResult.STRING_TYPE
:字串 -
XPathResult.BOOLEAN_TYPE
:布林值 -
XPathResult.UNORDERED_NODE_ITERATOR_TYPE
:無序的匹配節點集合 -
XPathResult.ORDERED_NODE_ITERATOR_TYPE
:有序的節點匹配集合 -
XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE
:無序的匹配節點快照集合 -
XPathResult.ORDERD_NODE_SNAPSHOT_TYPE
:有序的匹配節點快照集合 -
XPathResult.ANY_UNORDERED_NODE_TYPE
:返回匹配的節點集合,順序會與原文不一定一致。 -
XPathResult.FIRST_ORDERED_NODE_TYPE
:返回一個節點的集合
指定的結果型別決定了如何取得結果的值。
var result = xmldom.evaluate("employee/name", xmldom.documentElement, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
if (result !== null) {
var node = result.iterateNext();
while (node) {
alert(node.tagName);
node = result.iterateNext();
}
}
上述程式碼中返回的XPathResult點迭代器需要使用iterateNext()
方法從節點中取得匹配的節點。
再舉個例子如:
var xmldom = null;
var parser = new DOMParser();
xmldom = parser.parseFromString("<root><name>Oliver</name><name>Troy</name></root>","text/xml");
var result = xmldom.evaluate("/root/name", xmldom.documentElement, null, XPathResult.ORDERED_NODE_ITETATOR_TYPE, null);
if (result !== null) {
var node = result.iterateNext();
while (node) {
console.log(node.innerHTML);
node = result.iterateNext();
}
}
如果指定的是快照結果型別,就必須使用
-
snapshotItem()
方法和 -
snapshotLength
屬性。
如:
var result = xmldom.evaluate("employee/name", xmldom.documentElement, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
if (result !== null) {
for (var i = 0, len = result.snapshotLength; i < len; i++) {
alert(result.snapshotItem(i).tagName);
}
}
又如:
var xmldom = null;
var parser = new DOMParser();
xmldom = parser.parseFromString("<root><name>Oliver</name><name>Troy</name></root>", "text/xml");
var result = xmldom.evaluate("/root/name", xmldom.documentElement, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
if (result !== null) {
for (var i = 0, len = result.snapshotLength; i < len; i++) {
console.log(result.snapshotItem(i).innerHTML);
};
}
單節點結果
XPathResult.FIRST_ORDERED_NODE_TYPE
會返回一個匹配的節點,可以通過結果的singleNodeValue
屬性來訪問該節點。
var xmldom = null;
var parser = new DOMParser();
xmldom = parser.parseFromString("<root><name>Oliver</name><name>Troy</name></root>", "text/xml");
var result = xmldom.evaluate("/root/name", xmldom.documentElement, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
console.log(result.singleNodeValue.innerHTML); //Oliver
可以通過singleNodeValue
屬性來訪問該節點。
簡單型別結果
簡單型別的結果分別會通過
-
booleanValue
-
numberValue
-
stringValue
來訪問。
XPathResult.BOOLEAN_TYPE
:
對於布林值型別,如果至少有一個節點與XPath表示式匹配,則求值結果返回true,否則返回false:
var xmldom = null;
var parser = new DOMParser();
xmldom = parser.parseFromString("<root><name>Oliver</name><name>Troy</name></root>", "text/xml");
var result = xmldom.evaluate("/root/name", xmldom.documentElement, null, XPathResult.BOOLEAN_TYPE, null);
console.log(result.booleanValue); //True
如果有節點匹配”employee/name”,則返回true;
XPathResult.NUMBER_TYPE
和count()
方法:
var xmldom = null;
var parser = new DOMParser();
xmldom = parser.parseFromString("<root><name>Oliver</name><name>Troy</name></root>", "text/xml");
var result = xmldom.evaluate("count(/root/name)", xmldom.documentElement, null, XPathResult.NUMBER_TYPE, null);
console.log(result.numberValue); //2
以上輸出與XPath語法匹配的節點數量(2)
XPathResult.STRING_TYPE
:
var xmldom = null;
var parser = new DOMParser();
xmldom = parser.parseFromString("<root><name>Oliver</name><name>Troy</name></root>", "text/xml");
var result = xmldom.evaluate("/root/name", xmldom.documentElement, null, XPathResult.STRING_TYPE, null);
console.log(result.stringValue); //Oliver
預設型別結果
-
XPathResult.ANY_TYPE
常量
可以自動確定返回結果的型別。
-
resultType
屬性
可以檢測結果的型別。
如:
var xmldom = null;
var parser = new DOMParser();
xmldom = parser.parseFromString("<root><name>Oliver</name><name>Troy</name></root>", "text/xml");
var result = xmldom.evaluate("/root/name", xmldom.documentElement, null, XPathResult.ANY_TYPE, null);
if (result !== null) {
switch (result.resultType) {
case XPathResult.STRING_TYPE:
console.log(result.stringValue);
break;
case XPathResult.UNORDERED_NODE_ITERATOR_TYPE:
var node = result.iterateNext();
while (node) {
console.log(node.innerHTML);
node = result.iterateNext();
}
break;
}
}
對使用名稱空間的XML求值的方法:
-
createNSResolver()
方法
和建立一個函式,兩種方法
-
通過
createNSResolver(node)
方法來建立XPathNSResolver
物件, 然後再使用evaluate() 方法來獲取結果
如:
var nsresolver = xmldom.createNSResolver(xmldom.documentElement);
var result = xmldom.evaluate("wrox:book/wrox:author", xmldom.documentElement, nsresolver, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
alert(result.snapshotLength);
-
定義一個函式, 讓它接收一個名稱空間字首, 返回關聯的URI
如:
var neresolver = function(prefix) {
switch (prefix) {
case "wrox":
return "http://www.wrox.com/";
//其他字首
}
}
var result = xmldom.evaluate("count(wrox:book/wrox/author)", xmldom.documentElement, nsresolver, XPathResult.NUMBER_TYPE, null);
alert(result.numberValue);
跨瀏覽器使用XPath
第一個跨瀏覽器的方法是selectSingleNode()
, 接收三個引數: 上下文節點, XPath表示式, 可選的名稱空間
function selectSingleNode(context, expression, namespace) {
var doc = (context.nodeType != 9 ? context.ownerDocument : context);
if (typeof doc.evaluate != "umdefined") {
var nsresolver = null;
if (namespace instanceof Object) {
nsresolver = function(prefix) {
return namespace[prefix];
};
}
var result = doc.evaluate(expression, context, nsresolver, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
return (result !== null ? result.singleNodeValue : null);
} else if (typeof context.selectSingleNode != "undefined") {
if (namespace instanceof Object) {
var ns = "";
for (var prefix in namespace) {
if (namespaces.hasOwnProperty(prefix)) {
ns += "xmlns:" + prefix + "=`" + namespaces[prefix] + "` ";
}
}
doc.setProperty("SelectionNamespaces": ns);
}
return context.selectSingleNode(expression);
} else {
throw new Error("no XPath engine found");
}
}
下面是這個函式的使用示例:
var result = selectSingleNode(xmldom.documentElement, "wrox:book/wrox:author", {
wrox: "http://www.wrox.com/"
});
alert(serializeXml(result));
下面的函式是跨瀏覽器封裝的selectNodes()
函式, 這個函式接收與上一個函式有相同的三個引數。
function selectNodes(context, expression, namespace) {
var doc = (context.nodeType != 9 ? context.ownerDocument : context);
if (typeof doc.evaluate != "umdefined") {
var nsresolver = null;
if (namespace instanceof Object) {
nsresolver = function(prefix) {
return namespace[prefix];
};
}
var result = doc.evaluate(expression, context, nsresolver, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
var nodes = new Array();
if (result !== null) {
for (var i = 0, len = result.snapshotLength; i < len; i++) {
nodes.push(result.snapshotItem(i));
}
}
return nodes;
} else if (typeof context.selectSingleNode != "undefined") {
if (namespace instanceof Object) {
var ns = "";
for (var prefix in namespace) {
if (namespace.hasOwnProperty(prefix)) {
ns += "xmlns:" + prefix + "=`" + namespaces[prefix] + "` ";
}
}
doc.setProperty("SelectionNamespaces": ns);
}
var result = context.selectNodes(expression);
var nodes = new Array();
for (var i = 0, len = result.length; i < len; i++) {
nodes.push(result[i]);
}
return nodes;
} else {
throw new Error("no XPath engine found");
}
}
下面是selectNodes() 方法的使用示例:
var result = selectNodes(xmldom.documentElement, "wrox:book/wrox:author", {
wrox: "http://www.wrox.com/"
});
alert(result.length);