27、浏览器中的XPath

因为XML胜于处理是多种数据,所以必须有一种可以在XML代码中定位数据的方式。这就是XPath,它是专门用于定位匹配模式的一个或多个节点的小语言。

XPath简介

每个XPath表达式都有两部分:一个上下文节点为和一个节点模式。上下文节点人急偎亲了节点为模式的起始位置。节点为模式是由一个或多个节点选择器组成的字符串。

<?xml version="1.0"?>
<employees>
    <employee title="Software Engineer">
        <name>Nicholas C. Zakas</name>
    </employee>
    <employee title="Salesperson">
        <name>Jim Smith</name>
    </employee>
</employees>

 请看Xpath表达式:

employee/name

如果上下文节点是<employees/>,则上面的XPath表达式就匹配了<name>Nicholas...</name>和<name>Jim S...</name>。斜杠表示从父节点到子节点为的关系。这个XPath表达式表示:从<employees/>起,匹配位于<employee/>元素下的子节点<name/>元素。如果要选择<employee/>元素的每个<name/>元素,则表达式要变成:

employee[position()=1]/name

在XPath中,方框记号用于为某个节点为提供更加确切的信息。这个例子使用了XPath中的position()函数,它用于返回元素在父节点下的位置。第一个子节点的位置为1。

除了位置和名称外,还可以使用不同的方法来匹配元素。假设要选择所有title属性等于'Salesperson'的<employee/>元素,则XPath表达式变成:

employee[@title = 'Salesperson']

表达式中的@是attribute的缩写

XPath是一种十分强大的表达式可以令在DOM文档中查找指定节点为变得很容易。因为,IE和Mozilla都在DOM实现中引用了XPath支持。

IE中的XPath支持

微软的XML DOM中每个节点都有两个可用于获取匹配XPath模式的节点为的方法:selectNodes() ,用于返回匹配某个模式的节点的集合;selectSingleNode() ,用于返回匹配给定模式的第一个节点。

使用前面一节中的数据,可用下面的代码选择所有<employee/>元素下的<name/>元素:

//选择所有<employee/>元素下的<name/>元素
var lstNodes = oXmlDom.documentElement.selectNodes("employee/name");

因为这里selectNodes()是作为oXmlDom.documentElement的方法调用的,所以文档元素被看作XPath表达式的上下文节点

方法返回包含所有匹配给定模式的 NodeList 。下面我们可以这样迭代所有的元素:

for (var i = 0; i < lstNodes.length; i++) {
     alert(lstNodes[i]);
}

如果没有匹配给定模式的节点,还是会返回NodeList。如果为空,则它的length属性值等于0

 

如果只需要匹配模式的第一个元素,则可以使用selectSingleNode()。

var oElement = oXmlDom.documentElement.selectSingleNode("employee/name");

如果发现了节点,则selectSingleNode()方法返回一个Element,否则返回null

Mozilla中的XPath支持

Mozilla是根据DOM标准来实现对XPath的支持的。但比微软的复杂得多。

虽然有好多与XPath相关的对象,最重要的两个是:XPathEvaluator XPathResult

 

XPathEvaluator利用方法evaluate()计算XPath表达式,其方法定义如下:

 

evaluate(String expression , Node contextNode , XPathNSResolver resolver , short type , nsISupports result )

evaluate方法具有5个参数,其参数含义如下。

  • expression:XPath表达式。
  • contextNode:上下文节点,evaluate方法将在其内部进行查询。
  • resolver:命名空间解释函数,当XPath中存在命名空间时,需要指定该参数进行命名空间的解释。
  • type:结果类型,有10种不同的结果类型,分别对应于XPathResult对象中定义的10个常数。
  • result:该参数可以是一个存在的XPathResult对象,用于保存XPath查询的结果;也可以是null,evaluate方法将新建一个XPathResult对象来保存结果。

命名空间解释程序,只有在XML代码用到了XML命名空间时才是必要的,所以通常为空,置为null。

 

返回结果类型是以下十个常量之一:

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 ——返回节点集合快照,在文档外捕获节点,这样将来对文档的任何修改都不会影响这个节点列表。节点集合中的节点与它们出现在文档中的顺序不一定一样

 

指定的结果类型决定了如何获取结果的值。下面是个典型的例子:

var oEvaluator = new XPathEvaluator();
var oResult = oEvaluator.evaluate("employee/name", oXmlDom.documentElement,
						 null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
if (oResult != null) {
	var oElement = oResult.iterateNext();
	while (oElement) {
		alert(oElement.tagName);
		oElement = oResult.iterateNext();
	}
}
 

这个例子使用了XPathResult.ORDERED_NODE_ITERATOR_TYPE 结果,它是最常用到的结果类型。如果没有节点匹配XPath表达式,evaluate()返回null ,否则,它返回一个XPathResult对象,如果结果是个节点迭代子,不管它是有序还是无序的,都可以不断用iterateNext()方法获取在结果中的每个匹配结果 如果没有更多的匹配的节点,iterateNext()返回null

 

可以用节点迭代子为模拟微软为Mozilla创建一个selectNodes()方法:

if (isMoz) {
	Element.prototype.selectNodes = function (sXPath) {
		var oEvaluator = new XPathEvaluator();
		var oResult = oEvaluator.evaluate(sXPath, this,
		 null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
		var aNodes = new Array;
		if (oResult != null) {
			var oElement = oResult.iterateNext();
			while (oElement) {
				aNodes.push(oElement);
				oElement = oResult.iterateNext();
			}
		}
		return aNodes;
	};
	Document.prototype.selectNodes = Element.prototype.selectNodes;
}

 给Element类添加selectNodes()方法以模仿IE中的行为。调用evaluate()时,把用this关键字作为上下文节点(这也是IE的工作方式) ,然后,在结果数组中放入匹配的节点。新的方法使用如下:

var aNodes = oXmlDom.documentElement.selectNodes("employee/name");
for (var i = 0; i < aNodes.length; i++) {
	alert(aNodes[i].xml);
}

 

如果指定了XPathResult.ORDERED_NODE_SNAPSHOT_TYPE 快照结果类型(不管是有序的还是无序的),都可使用snapshotItem()以及snapshotLength()方法 ,如下例所示:

var oEvaluator = new XPathEvaluator();
var oResult = oEvaluator.evaluate('employee/name', oXmlDom.documentElement,
			 			null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
if (oResult != null) {
	for(var i = 0; i < oResult.snapshotLength; i++){
		alert(oResult.snapshotItem(i).tagName);
	}
}

在这个例子中,snapshotLength返回节点的数量,snapshotItem()返回快照中给定位置上的节点(类似于NodeList的length和item())

 

XPathResult.FIRST_ORDERED_NODE_TYPE 结果返回每个匹配的节点,可通过singNodeValue 属性来访问:

var oEvaluator = new XPathEvaluator();
var oResult = oEvaluator.evaluate('employee/name', oXmlDom.documentElement,
			 			null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
alert(oResult.singleNodeValue.xml);

这段代码可用来模拟IE的selectSingleNode()方法:

if (isMoz) {	
	Element.prototype.selectSingleNode = function (sXPath) {
		var oEvaluator = new XPathEvaluator();
		var oResult = oEvaluator.evaluate(sXPath, this,
		 null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
		if (oResult != null) {
			return oResult.singleNodeValue;
		} else {
			return null;
		}
	};
	Document.prototype.selectSingleNode = Element.prototype.selectSingleNode;
}
 

 这个方法的用法与在IE中的一样:

alert(oXmlDom.documentElement.selectSingleNode("employee/name"));

 

XPathResult类型最后部分是布尔类型、数字类型与字符串类型。其中,每个结果类型中都用相应的 booleanValue numberValue stringValue 来返回单个值。

 

对于布尔类型XPathResult.BOOLEAN_TYPE ,一般返回true,只需有一个节点匹配了XPath表达式,否则返回false:

var oEvaluator = new XPathEvaluator();
var oResult = oEvaluator.evaluate("employee/name", oXmlDom.documentElement, null, XPathResult.BOOLEAN_TYPE, null);
alert(oResult.booleanValue);

 在此例中,如果任何节点匹配了 'employee/name',booleanValue属性都会等于true。

 

对于数字类型XPathResult.NUMBER_TYPE ,XPath表达式必须使用返回数字的XPath函数,诸如count() ,它可用于计算匹配给定模式的节点的个数:

var oEvaluator = new XPathEvaluator();
var oResult = oEvaluator.evaluate("count(employee/name)", oXmlDom.documentElement, null, XPathResult.NUMBER_TYPE, null);
alert(oResult.numberValue);

 这段代码输出了匹配模式 'employee/name'(2个)。如果不使用这种特殊的XPath函数来使用这个方法,numberValue则为NaN。

 

对于字符串类型XPathResult.STRING_TYPE ,evaluate()方法查找每个匹配XPath表达式的节点,然后返回第一个子节点的值(假设第一个子节点是文本节点),否则结果是空字符串。例:

var oEvaluator = new XPathEvaluator();
var oResult = oEvaluator.evaluate("employee/name", oXmlDom.documentElement, null, XPathResult.STRING_TYPE, null);
alert(oResult.stringValue);

 代码将输出'Nicholas C.Zakas',因为这是在<employee/>元素下<name/>元素中的第一个文本节点。

 

另外,可以使用XPathResult.ANY_TYPE ,这将使evaluate()根据XPath表达式返回最合适的结果类型 。一般来说,这个结果类型是个布尔值,字符串值或都是无序的节点迭代子。要判断返回结果类型的真真类型,可使用resultType 属性:

var oEvaluator = new XPathEvaluator();
var oResult = oEvaluator.evaluate("employee/name", oXmlDom.documentElement, null, XPathResult.ANY_TYPE, null);
if(oResult != null){
	switch(oResult.resultType){
		case XPathResult.STRING_TYPE:
			//处理字符串类型 ...
			break;
		case XPathResult.NUMBER_TYPE:
			//处理数字类型 ...
			break;
		case XPathResult.BOOLEAN_TYPE:
			//处理布尔类型 ...
			break;
		case XPathResult.UNORDERED_NODE_ITERATOR_TYPE:
			//处理迭代类型 ...
			break;
		default:
			//处理其他类型
	}
}

 

从上面一些示例可以看出,Mozilla中的XPath计算远比IE的复杂,当然也更加强大,通过使用自定义的 selectNodes() 和 selectSingleNode()方法,可以在两种浏览器上使用同样的代码进行XPath计算。

 

Mozilla上XPath命名空间的支持

对于具有命名空间的XML文档,进行XPath查询时必须指定resolver参数,用于解释命名空间的URI。

 

<?xml version="1.0" encoding="UTF-8"?>
<Books xmlns:pub="http://www.pub.com" xmlns:author="http://www.author.com">

    <pub:Book>
        <Title>Ajax In Action</Title>
        <author:Author>Dave Crane</author:Author>
    </pub:Book>
    
    <pub:Book>
        <Title>Professional Ajax</Title>
        <author:Author>Nicholas C.Zakas</author:Author>
    </pub:Book>
    
</Books>
 

定义nsResolver函数如下,其作用是根据输入的prefix参数返回相应的命名空间URI字符串。

function nsResolver(prefix) {

    // 命名空间的名称/URI对
    var ns = {
        "pub": "http://www.pub.com",
        "author": "http://www.author.com"
    };

    // 根据命名空间的前缀返回其URI
    return ns[prefix] || null;
}

在books_ns.xml中查询所有<Author>节点的XPath表达式为:
/Books/pub:Book/author:Author

 

进行XPath查询的代码如下:

<script type="text/javascript" src="detect.js"></script>
<script type="text/javascript" src="xmldom.js"></script>
<script type="text/javascript">
	function nsResolver(prefix) {
	    // 命名空间的名称/URI对
	    var ns = {
	        "pub": "http://www.pub.com",
	        "author": "http://www.author.com"
	    };
	
	    // 根据命名空间的前缀返回其URI
	    return ns[prefix] || null;
	}
	
	var oXmlDom = new XmlDom();
	oXmlDom.onreadystatechange = function () {
		if (oXmlDom.readyState == 4 || (oXmlDom.getReadyState && oXmlDom.getReadyState() == 4)) {
			// 创建XPathEvaluator对象
			var xpe =  new XPathEvaluator();
			
			// 查询<Author>节点
			var iterator = xpe.evaluate("/Books/pub:Book/author:Author", oXmlDom,
			
			nsResolver, XPathResult.ANY_TYPE, null);
			
			// 获取查询结果
			var node;
			while (node = iterator.iterateNext()) {		
				// 输出节点的XML字符串
				alert(node.xml);		
			}
		}
	};
	oXmlDom.load("test.xml");
</script>
 

Mozilla上运行结果:




 
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值