JavaScript - XPath 总结

markdown

XPath 是一种节点查找手段。它比使用 标准DOM 去查找 XML 节点更加方便、更加简单。但是 XPath 是 DOM3 中才支持的标准,并且 IE 有自己的实现方式。(IE总是自己造马车)

IE中的XPath

IE 提供了两种方法:
1、selectSingleNode() 获取单一节点

1
2
3
4
5
6
var xmlStr = '<root><user id="1">Tom</user><user id="2">Lucy</user></root>';
var xmlDom = parseXML(xmlStr); //创建xmlDom对象
var node = xmlDom.selectSingleNode('root/user'); //种方式称为节点树查找,必须从最外层开始,由外向内
//只会获得第一个 user
alert(node.tagName); //user

2、selectNodes() 获取节点集合

1
2
3
4
5
var nodes = xmlDom.selectNodes('root/user'); //返回的是一个数组
alert(nodes.length); //2
//一般这样用
var nodes = xmlDom.selectNodes('root[1]/user'); //获取第二个root下的所有user

W3C中的XPath

在 DOM3 中 XPath 规范中,最重要的两个类型是 XPathEvaluator 和 XPathResult 。其中 XPathEvaluator 用于在特定上下文对 XPath 表达式求值。

XPathEvaluator 方法一共需要传递五个参数:
1.XPath路径; 2.上下文节点; 3.命名空间求解器(null); 4.返回结果类型; 5.保存结果的 XPath 对象(null);
获取成功就返回对应的类型值,获取失败返回 null。

返回的结果类型一共有十种,常用的就两种:

常量
XPathResult_FIRST_ORDERED_NODE_TYPE 返回单一节点
XPathResult_ORDERED_NODE_ITERATOR_TYPE 返回节点集合

获取单一节点

1
2
3
4
var result = xmlDom.evaluate('root/user',xmlDom,null,XPathResult.FIRST_ORDERED_NODE_TYPE,null);
if(result !== null){
alert(result.singleNodeValue.textContent); //Tom
}

获取节点集合

获取的时候只需要把返回值的类型修改为 获取节点集合 即可。
得到的节点集合需要用 iterateNext() 方法使用迭代方法存入一个数组。这样就可以对数据进行操作了。

1
2
3
4
5
6
7
8
9
10
var result = xmlDom.evaluate('root/user',xmlDom,null,XPathResult.ORDERED_NODE_ITERATOR_TYPE,null);
if(result !== null){
var nodes = [];
var node = result.iterateNext();
while(node !== null){
nodes.push(node);
node = result.iterateNext();
}
console.log(nodes[1].innerHTML); //Lucy
}

XPath 常用语法

XML加载之后就可以使用标准DOM来进行各种操作,比如上面的返回 tagName 。当然 XPath 也提供了一套方法:(这里只列举最常用的)
1、相同标签问题

1
2
var node = xmlDom.selectSingleNode('root/user[1]');
alert(serializeXML(node)); //<user id="2">Lucy</user> 第二个user

IE中下标从 0 开始!! W3C中下标从 1 开始!!

2、获取元素内文本

1
2
var node = xmlDom.selectSingleNode('root/user/text()');
alert(serializeXML(node)); //Tom

3、跨结构查找(不关心结构层次)

1
2
3
var node = xmlDom.selectSingleNode('//user'); //查找整个文档中第一个user
var node = xmlDom.selectSingleNode('b//user'); //也可以限制在一个标签内查找
alert(serializeXML(node));

4、通过属性查找

1
2
var node = xmlDom.selectSingleNode('root/user[@id=2]');
alert(serializeXML(node)); //<user id="2">Tom</user>

跨浏览器兼容

鉴于IE中的相对功能较少,首先考虑 W3C。

获取单一节点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//获取单一节点
function selectSingleNode(xmlDom,xpath){
var node = null;
if(typeof xmlDom.evaluate != 'undefined'){ //W3C
//让下标从 0 开始
var patten = /\[(\d+)\]/;
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'){ //IE
node = xmlDom.selectSingleNode(xpath);
}
return node;
}

获取节点集合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//获取节点集合
function selectNodes(xmlDom,xpath){
var nodes = [];
if(typeof xmlDom.evaluate != 'undefined'){ //W3C
//让下标从 0 开始
var patten = /\[(\d+)\]/;
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.ORDERED_NODE_ITERATOR_TYPE,null);
if(result !== null){
var node = null;
while((node = result.iterateNext())!= null){
nodes.push(node);
}
}
}else if(typeof xmlDom.selectNodes != 'undefined'){ //IE
nodes = xmlDom.selectNodes(xpath);
}
return nodes;
}