javascript XPath 实现
关于XPath的相关知识可以参看http://www.w3school.com.cn/xpath/index.asp
在进行XPath之前要对xml文档进行加载。如何加载可参看上篇文章。
- var oXmlDom = XmlDom();
- oXmlDom.load("exam1.xml");
针对IE,当在读取XML文档后,本身的对象提供了两个方法用于接收XPATH表达式。分别是:selectNodes及 selectSingleNode,这两个方法是作为oXmlDom.documentElement的方法调用的。相对Mozilla比较简单,当然功能是没有Mozilla实现XPATH的功能强大。
- oXmlDom.documentElement.selectNodes(xPath)
- oXmlDom.documentElement.selectSingleNode(xPath)
Mozilla实现XPATH的方式则相对比较复杂。需要创建XPathEvaluator对象,然后调用evaluate方法执行XPATH表达式。evaluate包含五个参数:XPath表达式、上下文节点、命名空间解释程序及返回的结果类型,同时在XPathResult中存放结果(通常为 null)命名空间解释程序通常留空。返回结果类型有:
XPathResult.ANY_TYPE——返回符合XPath表达式类型的数据;
XPathResult.ANY_UNORDERED_NODE_TYPE——返回匹配节点的节点集合,但顺序可能与文档中不同
XPathResult.BOOLEAN_TYPE——返回布尔值
XPathResult.FIRST_OREDERED_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——返回节点集合快照,但顺序可能与文档中不同
下面针对Mozilla实现selectNodes及selectSingleNode方法。由于oXmlDom.documentElement 为Elment对象,那么为了用相同的代码兼容IE及Mozilla,可以将selectNodes及selectSingleNode作为 Element的属性。代码如下:
- /**
- * 查找匹配XPath表达式的节点(Mozilla实现selectNodes方法;IE自带该方法)
- *
- * @param sXPath
- * XPAHT表达式
- * @return 节点集合数组 Array<Element>
- */
- 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;
- };
- /**
- * 查找第一个匹配XPath表达式的节点(Mozilla实现selectSingleNode方法;IE自带该方法)
- *
- * @param sXPath
- * XPAHT表达式
- * @return 节点元素对象 instanceof Element is true
- */
- 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;
- }
- };
- /**
- * 查找匹配XPath表达式的节点(Mozilla实现selectNodes方法;IE自带该方法)
- *
- * @param sXPath
- * XPAHT表达式
- * @return 节点集合数组 Array<Element>
- */
- 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;
- };
- /**
- * 查找第一个匹配XPath表达式的节点(Mozilla实现selectSingleNode方法;IE自带该方法)
- *
- * @param sXPath
- * XPAHT表达式
- * @return 节点元素对象 instanceof Element is true
- */
- 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;
- }
- };
/** * 查找匹配XPath表达式的节点(Mozilla实现selectNodes方法;IE自带该方法) * * @param sXPath * XPAHT表达式 * @return 节点集合数组 Array<Element> */ 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; }; /** * 查找第一个匹配XPath表达式的节点(Mozilla实现selectSingleNode方法;IE自带该方法) * * @param sXPath * XPAHT表达式 * @return 节点元素对象 instanceof Element is true */ 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; } };
这样我们就完成了Mozilla对XPath的实现。
当然Mozilla本身实现的XPath的操作要比单纯的IE提供的selectNodes及selectSingleNode方法更强大,而且对与XPath表达式的支持也更好。我们可以再扩充一些方法,但注意了,下面这些方法只能在支持Mozilla的浏览器中使用:
- /**
- * 统计匹配指定模式的节点个数(该方法仅限于Mozilla)
- *
- * @param sXPath
- * XPAHT表达式
- * @return 返回匹配节点个数。如没有匹配则返回0
- */
- Element.prototype.count = function(sXPath) {
- var __count = 0;
- sXPath = "count(" + sXPath + ")";
- var oEvaluator = new XPathEvaluator();
- var oResult = oEvaluator.evaluate(sXPath, this, null,
- XPathResult.NUMBER_TYPE, null);
- if (oResult) {
- __count = oResult.numberValue;
- }
- return __count;
- };
- /**
- * 判断指定XPath表达式是否有匹配节点(该方法仅限于Mozilla)
- *
- * @param sXPath
- * XPAHT表达式
- * @return true|false
- */
- Element.prototype.isMatch = function(sXPath) {
- var oEvaluator = new XPathEvaluator();
- var oResult = oEvaluator.evaluate(sXPath, this, null,
- XPathResult.BOOLEAN_TYPE, null);
- return oResult.booleanValue;
- };
- /**
- * 统计匹配指定模式的节点个数(该方法仅限于Mozilla)
- *
- * @param sXPath
- * XPAHT表达式
- * @return 返回匹配节点个数。如没有匹配则返回0
- */
- Element.prototype.count = function(sXPath) {
- var __count = 0;
- sXPath = "count(" + sXPath + ")";
- var oEvaluator = new XPathEvaluator();
- var oResult = oEvaluator.evaluate(sXPath, this, null,
- XPathResult.NUMBER_TYPE, null);
- if (oResult) {
- __count = oResult.numberValue;
- }
- return __count;
- };
- /**
- * 判断指定XPath表达式是否有匹配节点(该方法仅限于Mozilla)
- *
- * @param sXPath
- * XPAHT表达式
- * @return true|false
- */
- Element.prototype.isMatch = function(sXPath) {
- var oEvaluator = new XPathEvaluator();
- var oResult = oEvaluator.evaluate(sXPath, this, null,
- XPathResult.BOOLEAN_TYPE, null);
- return oResult.booleanValue;
- };
/** * 统计匹配指定模式的节点个数(该方法仅限于Mozilla) * * @param sXPath * XPAHT表达式 * @return 返回匹配节点个数。如没有匹配则返回0 */ Element.prototype.count = function(sXPath) { var __count = 0; sXPath = "count(" + sXPath + ")"; var oEvaluator = new XPathEvaluator(); var oResult = oEvaluator.evaluate(sXPath, this, null, XPathResult.NUMBER_TYPE, null); if (oResult) { __count = oResult.numberValue; } return __count; }; /** * 判断指定XPath表达式是否有匹配节点(该方法仅限于Mozilla) * * @param sXPath * XPAHT表达式 * @return true|false */ Element.prototype.isMatch = function(sXPath) { var oEvaluator = new XPathEvaluator(); var oResult = oEvaluator.evaluate(sXPath, this, null, XPathResult.BOOLEAN_TYPE, null); return oResult.booleanValue; };
当然上述方法,如果是在IE中,可以同过IE提供最基本的两个方法解决,这里就不多做赘述。
下面我们最完成的代码做下测试,看下上述编码对与XPath语法的支持情况,为此做如下测试页面
- <?xml version="1.0" encoding="UTF-8" ?>
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
- <html xmlns="http://www.w3.org/1999/xhtml">
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
- <mce:style type="text/css"><!--
- #hea {
- border: 1px dotted orange;
- }
- #xml {
- float: left;
- width: 400px;
- height: 600px;
- border: 1px dotted red;
- }
- #res {
- float: left;
- border: 1px solid green;
- width: 500px;
- height: 600px;
- }
- --></mce:style><style type="text/css" mce_bogus="1">#hea {
- border: 1px dotted orange;
- }
- #xml {
- float: left;
- width: 400px;
- height: 600px;
- border: 1px dotted red;
- }
- #res {
- float: left;
- border: 1px solid green;
- width: 500px;
- height: 600px;
- }</style>
- <mce:script type="text/javascript" src="loadxml.js" mce_src="loadxml.js"></mce:script>
- <title>Insert title here</title>
- <mce:script type="text/javascript"><!--
- function search(xPath) {
- var oXmlDom = XmlDom();
- oXmlDom.onreadystatechange = function() {
- //IE|FF
- if (oXmlDom.readyState == 4 || oXmlDom.readyState == "complete") {
- }
- }
- oXmlDom.load("exam1.xml");
- var aNodes = oXmlDom.documentElement.selectNodes(xPath);
- var sRes = "";
- for ( var index = 0; index < aNodes.length; index++) {
- sRes += aNodes[index].xml + "/r/n";
- }
- var oDiv = document.getElementById('res');
- oDiv.innerHTML = "";
- var xml = document.createTextNode(sRes);
- oDiv.appendChild(xml);
- }
- // --></mce:script>
- </head>
- <body>
- <div id="hea">
- XPath表达式:<input type="text" name="sql" id="sql" size="60" /> <input
- type="button" value="search"
- onclick="search(document.getElementById('sql').value);" /></div>
- <iframe src="exam1.xml" mce_src="exam1.xml" id="xml"></iframe>
- <div id="res"></div>
- </body>
- </html>
- <?xml version="1.0" encoding="UTF-8" ?>
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
- <html xmlns="http://www.w3.org/1999/xhtml">
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
- <style type="text/css">
- #hea {
- border: 1px dotted orange;
- }
- #xml {
- float: left;
- width: 400px;
- height: 600px;
- border: 1px dotted red;
- }
- #res {
- float: left;
- border: 1px solid green;
- width: 500px;
- height: 600px;
- }
- </style>
- <script type="text/javascript" src="loadxml.js"></script>
- <title>Insert title here</title>
- <script type="text/javascript">
- function search(xPath) {
- var oXmlDom = XmlDom();
- oXmlDom.onreadystatechange = function() {
- //IE|FF
- if (oXmlDom.readyState == 4 || oXmlDom.readyState == "complete") {
- }
- }
- oXmlDom.load("exam1.xml");
- var aNodes = oXmlDom.documentElement.selectNodes(xPath);
- var sRes = "";
- for ( var index = 0; index < aNodes.length; index++) {
- sRes += aNodes[index].xml + "/r/n";
- }
- var oDiv = document.getElementById('res');
- oDiv.innerHTML = "";
- var xml = document.createTextNode(sRes);
- oDiv.appendChild(xml);
- }
- </script>
- </head>
- <body>
- <div id="hea">
- XPath表达式:<input type="text" name="sql" id="sql" size="60" /> <input
- type="button" value="search"
- onclick="search(document.getElementById('sql').value);" /></div>
- <iframe src="exam1.xml" id="xml"></iframe>
- <div id="res"></div>
- </body>
- </html>
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <style type="text/css"> #hea { border: 1px dotted orange; } #xml { float: left; width: 400px; height: 600px; border: 1px dotted red; } #res { float: left; border: 1px solid green; width: 500px; height: 600px; } </style> <script type="text/javascript" src="loadxml.js"></script> <title>Insert title here</title> <script type="text/javascript"> function search(xPath) { var oXmlDom = XmlDom(); oXmlDom.onreadystatechange = function() { //IE|FF if (oXmlDom.readyState == 4 || oXmlDom.readyState == "complete") { } } oXmlDom.load("exam1.xml"); var aNodes = oXmlDom.documentElement.selectNodes(xPath); var sRes = ""; for ( var index = 0; index < aNodes.length; index++) { sRes += aNodes[index].xml + "/r/n"; } var oDiv = document.getElementById('res'); oDiv.innerHTML = ""; var xml = document.createTextNode(sRes); oDiv.appendChild(xml); } </script> </head> <body> <div id="hea"> XPath表达式:<input type="text" name="sql" id="sql" size="60" /> <input type="button" value="search" onclick="search(document.getElementById('sql').value);" /></div> <iframe src="exam1.xml" id="xml"></iframe> <div id="res"></div> </body> </html>
exam1.xml源文件如下:
- <?xml version="1.0" encoding="UTF-8"?>
- <exam>
- <no id="1">
- <question1>我喜欢与历史学家交往<q>ceshi</q></question1>
- <question2>我做事进度较慢,但确保成效</question2>
- <value>4</value>
- </no>
- <no id="2">
- <question1>我想要每个人都喜欢我</question1>
- <question2>我一贯努力工作</question2>
- <value>7</value>
- </no>
- <no id="3">
- <question1>我力争第一</question1>
- <question2>我思考自身的长处</question2>
- </no>
- <no id="4">
- <question1>我思考有待改进之处</question1>
- <question2>我是一个偏重情感的人</question2>
- </no>
- <no id="5">
- <question1>我能够接受多种类型的人</question1>
- <question2>我想念我的朋友</question2>
- </no>
- <no id="6">
- <question1>与陌生人交谈使我兴奋</question1>
- <question2>我认为自己很能干</question2>
- </no>
- <no id="7">
- <question1>我通过与新人建立联系获得满足感</question1>
- <question2>竞争与挑战让我感到兴奋</question2>
- </no>
- <no id="8">
- <question1>成为他人的知己使我满足</question1>
- <question2>我信守自己的价值观</question2>
- </no>
- </exam>
- <?xml version="1.0" encoding="UTF-8"?>
- <exam>
- <no id="1">
- <question1>我喜欢与历史学家交往<q>ceshi</q></question1>
- <question2>我做事进度较慢,但确保成效</question2>
- <value>4</value>
- </no>
- <no id="2">
- <question1>我想要每个人都喜欢我</question1>
- <question2>我一贯努力工作</question2>
- <value>7</value>
- </no>
- <no id="3">
- <question1>我力争第一</question1>
- <question2>我思考自身的长处</question2>
- </no>
- <no id="4">
- <question1>我思考有待改进之处</question1>
- <question2>我是一个偏重情感的人</question2>
- </no>
- <no id="5">
- <question1>我能够接受多种类型的人</question1>
- <question2>我想念我的朋友</question2>
- </no>
- <no id="6">
- <question1>与陌生人交谈使我兴奋</question1>
- <question2>我认为自己很能干</question2>
- </no>
- <no id="7">
- <question1>我通过与新人建立联系获得满足感</question1>
- <question2>竞争与挑战让我感到兴奋</question2>
- </no>
- <no id="8">
- <question1>成为他人的知己使我满足</question1>
- <question2>我信守自己的价值观</question2>
- </no>
- </exam>
<?xml version="1.0" encoding="UTF-8"?> <exam> <no id="1"> <question1>我喜欢与历史学家交往<q>ceshi</q></question1> <question2>我做事进度较慢,但确保成效</question2> <value>4</value> </no> <no id="2"> <question1>我想要每个人都喜欢我</question1> <question2>我一贯努力工作</question2> <value>7</value> </no> <no id="3"> <question1>我力争第一</question1> <question2>我思考自身的长处</question2> </no> <no id="4"> <question1>我思考有待改进之处</question1> <question2>我是一个偏重情感的人</question2> </no> <no id="5"> <question1>我能够接受多种类型的人</question1> <question2>我想念我的朋友</question2> </no> <no id="6"> <question1>与陌生人交谈使我兴奋</question1> <question2>我认为自己很能干</question2> </no> <no id="7"> <question1>我通过与新人建立联系获得满足感</question1> <question2>竞争与挑战让我感到兴奋</question2> </no> <no id="8"> <question1>成为他人的知己使我满足</question1> <question2>我信守自己的价值观</question2> </no> </exam>
我们可以在输入框中进行测试。使用XPath语法 进行测试,当然大部分语法都可以在FF中测试通过,但在IE中,显然对Xpath轴 是不支持的,同时对XPath谓语表达式中的last()、position()也是不支持的。
以下是一些测试语法,大家可以试下:
//IE /FF 均测试通过
//no 或者 /exam/no 选取所有no节点
//no[@id='1'] 选取no节点属性为1的节点
//no/* 选取no的所有子节点
//no[@*] 选取所有带有属性的no节点
//no[value>4] 选取no节点下value节点值大于4的no节点
//no/question1/q | //no[@id='2'] 选取no下question1中的q节点或着no节点属性为1的节点
//no/question1/text() 取no节点下所有的question1节点所包含的文本
//IE不支持XPath轴表达式
//ff
//no[last()-1] 选取倒数第一个no节点
//no[position()<3] 选择位置小于3的no节点
child::no 选取当前文档所有的no节点
//no/child::question1 选取no节点下所有的question1节点
//no/child::question1/child::text() 取no节点下所有的question1节点所包含的文本