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);
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。