javascript XPath 實現


關於XPath的相關知識可以參看http://www.w3school.com.cn/xpath/index.asp

在進行XPath之前要對xml文檔進行加載。如何加載可參看上篇文章。

[javascript] view plain copy print ?
  1. var oXmlDom = XmlDom();  
  2. oXmlDom.load("exam1.xml");  

 

針對IE,當在讀取XML文檔后,本身的對象提供了兩個方法用於接收XPATH表達式。分別是:selectNodes及 selectSingleNode,這兩個方法是作為oXmlDom.documentElement的方法調用的。相對Mozilla比較簡單,當然功能是沒有Mozilla實現XPATH的功能強大。

[javascript] view plain copy print ?
  1. oXmlDom.documentElement.selectNodes(xPath)    
  2. 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的屬性。代碼如下:

[javascript] view plain copy print ?
  1. /** 
  2.  * 查找匹配XPath表達式的節點(Mozilla實現selectNodes方法;IE自帶該方法) 
  3.  *  
  4.  * @param sXPath 
  5.  *            XPAHT表達式 
  6.  * @return 節點集合數組 Array<Element> 
  7.  */  
  8. Element.prototype.selectNodes = function(sXPath) {  
  9.     var oEvaluator = new XPathEvaluator();  
  10.     var oResult = oEvaluator.evaluate(sXPath, thisnull,  
  11.             XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);  
  12.     var aNodes = new Array();  
  13.     if (oResult != null) {  
  14.         var oElement = oResult.iterateNext();  
  15.         while (oElement) {  
  16.             aNodes.push(oElement);  
  17.             oElement = oResult.iterateNext();  
  18.         }  
  19.     }  
  20.     return aNodes;  
  21. };  
  22. /** 
  23.  * 查找第一個匹配XPath表達式的節點(Mozilla實現selectSingleNode方法;IE自帶該方法) 
  24.  *  
  25.  * @param sXPath 
  26.  *            XPAHT表達式 
  27.  * @return 節點元素對象 instanceof Element is true 
  28.  */  
  29. Element.prototype.selectSingleNode = function(sXPath) {  
  30.     var oEvaluator = new XPathEvaluator();  
  31.     var oResult = oEvaluator.evaluate(sXPath, thisnull,  
  32.             XPathResult.FIRST_ORDERED_NODE_TYPE, null);  
  33.     if (oResult != null) {  
  34.         return oResult.singleNodeValue;  
  35.     } else {  
  36.         return null;  
  37.     }  
  38. };  
  1. /** 
  2.  * 查找匹配XPath表達式的節點(Mozilla實現selectNodes方法;IE自帶該方法) 
  3.  *  
  4.  * @param sXPath 
  5.  *            XPAHT表達式 
  6.  * @return 節點集合數組 Array<Element> 
  7.  */  
  8. Element.prototype.selectNodes = function(sXPath) {  
  9.     var oEvaluator = new XPathEvaluator();  
  10.     var oResult = oEvaluator.evaluate(sXPath, thisnull,  
  11.             XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);  
  12.     var aNodes = new Array();  
  13.     if (oResult != null) {  
  14.         var oElement = oResult.iterateNext();  
  15.         while (oElement) {  
  16.             aNodes.push(oElement);  
  17.             oElement = oResult.iterateNext();  
  18.         }  
  19.     }  
  20.     return aNodes;  
  21. };  
  22. /** 
  23.  * 查找第一個匹配XPath表達式的節點(Mozilla實現selectSingleNode方法;IE自帶該方法) 
  24.  *  
  25.  * @param sXPath 
  26.  *            XPAHT表達式 
  27.  * @return 節點元素對象 instanceof Element is true 
  28.  */  
  29. Element.prototype.selectSingleNode = function(sXPath) {  
  30.     var oEvaluator = new XPathEvaluator();  
  31.     var oResult = oEvaluator.evaluate(sXPath, thisnull,  
  32.             XPathResult.FIRST_ORDERED_NODE_TYPE, null);  
  33.     if (oResult != null) {  
  34.         return oResult.singleNodeValue;  
  35.     } else {  
  36.         return null;  
  37.     }  
  38. };  
/**
 * 查找匹配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的瀏覽器中使用:

[javascript] view plain copy print ?
  1. /** 
  2.  * 統計匹配指定模式的節點個數(該方法僅限於Mozilla) 
  3.  *  
  4.  * @param sXPath 
  5.  *            XPAHT表達式 
  6.  * @return 返回匹配節點個數。如沒有匹配則返回0 
  7.  */  
  8. Element.prototype.count = function(sXPath) {  
  9.     var __count = 0;  
  10.     sXPath = "count(" + sXPath + ")";  
  11.     var oEvaluator = new XPathEvaluator();  
  12.     var oResult = oEvaluator.evaluate(sXPath, thisnull,  
  13.             XPathResult.NUMBER_TYPE, null);  
  14.     if (oResult) {  
  15.         __count = oResult.numberValue;  
  16.     }  
  17.     return __count;  
  18. };  
  19. /** 
  20.  * 判斷指定XPath表達式是否有匹配節點(該方法僅限於Mozilla) 
  21.  *  
  22.  * @param sXPath 
  23.  *            XPAHT表達式 
  24.  * @return true|false 
  25.  */  
  26. Element.prototype.isMatch = function(sXPath) {  
  27.     var oEvaluator = new XPathEvaluator();  
  28.     var oResult = oEvaluator.evaluate(sXPath, thisnull,  
  29.             XPathResult.BOOLEAN_TYPE, null);  
  30.     return oResult.booleanValue;  
  31. };  
  1. /** 
  2.  * 統計匹配指定模式的節點個數(該方法僅限於Mozilla) 
  3.  *  
  4.  * @param sXPath 
  5.  *            XPAHT表達式 
  6.  * @return 返回匹配節點個數。如沒有匹配則返回0 
  7.  */  
  8. Element.prototype.count = function(sXPath) {  
  9.     var __count = 0;  
  10.     sXPath = "count(" + sXPath + ")";  
  11.     var oEvaluator = new XPathEvaluator();  
  12.     var oResult = oEvaluator.evaluate(sXPath, thisnull,  
  13.             XPathResult.NUMBER_TYPE, null);  
  14.     if (oResult) {  
  15.         __count = oResult.numberValue;  
  16.     }  
  17.     return __count;  
  18. };  
  19. /** 
  20.  * 判斷指定XPath表達式是否有匹配節點(該方法僅限於Mozilla) 
  21.  *  
  22.  * @param sXPath 
  23.  *            XPAHT表達式 
  24.  * @return true|false 
  25.  */  
  26. Element.prototype.isMatch = function(sXPath) {  
  27.     var oEvaluator = new XPathEvaluator();  
  28.     var oResult = oEvaluator.evaluate(sXPath, thisnull,  
  29.             XPathResult.BOOLEAN_TYPE, null);  
  30.     return oResult.booleanValue;  
  31. };  
/**
 * 統計匹配指定模式的節點個數(該方法僅限於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語法的支持情況,為此做如下測試頁面

  1. <?xml version="1.0" encoding="UTF-8" ?>  
  2. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">  
  3. <html xmlns="http://www.w3.org/1999/xhtml">  
  4. <head>  
  5. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />  
  6. <mce:style type="text/css"><!--  
  7. #hea {  
  8.     border: 1px dotted orange;  
  9. }  
  10. #xml {  
  11.     float: left;  
  12.     width: 400px;  
  13.     height: 600px;  
  14.     border: 1px dotted red;  
  15. }  
  16. #res {  
  17.     float: left;  
  18.     border: 1px solid green;  
  19.     width: 500px;  
  20.     height: 600px;  
  21. }  
  22. --></mce:style><style type="text/css" mce_bogus="1">#hea {  
  23.     border: 1px dotted orange;  
  24. }  
  25. #xml {  
  26.     float: left;  
  27.     width: 400px;  
  28.     height: 600px;  
  29.     border: 1px dotted red;  
  30. }  
  31. #res {  
  32.     float: left;  
  33.     border: 1px solid green;  
  34.     width: 500px;  
  35.     height: 600px;  
  36. }</style>  
  37. <mce:script type="text/javascript" src="loadxml.js" mce_src="loadxml.js"></mce:script>  
  38. <title>Insert title here</title>  
  39. <mce:script type="text/javascript"><!--  
  40.       
  41.     function search(xPath) {  
  42.         var oXmlDom = XmlDom();  
  43.         oXmlDom.onreadystatechange = function() {  
  44.             //IE|FF  
  45.             if (oXmlDom.readyState == 4 || oXmlDom.readyState == "complete") {  
  46.             }  
  47.         }  
  48.         oXmlDom.load("exam1.xml");  
  49.         var aNodes = oXmlDom.documentElement.selectNodes(xPath);  
  50.         var sRes = "";  
  51.         for ( var index = 0; index < aNodes.length; index++) {  
  52.             sRes += aNodes[index].xml + "/r/n";  
  53.         }  
  54.         var oDiv = document.getElementById('res');  
  55.         oDiv.innerHTML = "";  
  56.         var xml = document.createTextNode(sRes);  
  57.         oDiv.appendChild(xml);  
  58.     }  
  59. // --></mce:script>  
  60. </head>  
  61. <body>  
  62. <div id="hea">  
  63. XPath表達式:<input type="text" name="sql" id="sql" size="60" /> <input  
  64.     type="button" value="search"  
  65.     onclick="search(document.getElementById('sql').value);" /></div>  
  66. <iframe src="exam1.xml" mce_src="exam1.xml" id="xml"></iframe>  
  67. <div id="res"></div>  
  68. </body>  
  69. </html>  
  1. <?xml version="1.0" encoding="UTF-8" ?>  
  2. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">  
  3. <html xmlns="http://www.w3.org/1999/xhtml">  
  4. <head>  
  5. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />  
  6. <style type="text/css">  
  7. #hea {  
  8.     border: 1px dotted orange;  
  9. }  
  10.   
  11. #xml {  
  12.     float: left;  
  13.     width: 400px;  
  14.     height: 600px;  
  15.     border: 1px dotted red;  
  16. }  
  17.   
  18. #res {  
  19.     float: left;  
  20.     border: 1px solid green;  
  21.     width: 500px;  
  22.     height: 600px;  
  23. }  
  24. </style>  
  25. <script type="text/javascript" src="loadxml.js"></script>  
  26. <title>Insert title here</title>  
  27. <script type="text/javascript">  
  28.       
  29.     function search(xPath) {  
  30.         var oXmlDom = XmlDom();  
  31.         oXmlDom.onreadystatechange = function() {  
  32.             //IE|FF  
  33.             if (oXmlDom.readyState == 4 || oXmlDom.readyState == "complete") {  
  34.   
  35.             }  
  36.         }  
  37.         oXmlDom.load("exam1.xml");  
  38.         var aNodes = oXmlDom.documentElement.selectNodes(xPath);  
  39.         var sRes = "";  
  40.         for ( var index = 0; index < aNodes.length; index++) {  
  41.             sRes += aNodes[index].xml + "/r/n";  
  42.         }  
  43.         var oDiv = document.getElementById('res');  
  44.         oDiv.innerHTML = "";  
  45.         var xml = document.createTextNode(sRes);  
  46.         oDiv.appendChild(xml);  
  47.     }  
  48. </script>  
  49. </head>  
  50. <body>  
  51. <div id="hea">  
  52. XPath表達式:<input type="text" name="sql" id="sql" size="60" /> <input  
  53.     type="button" value="search"  
  54.     onclick="search(document.getElementById('sql').value);" /></div>  
  55. <iframe src="exam1.xml" id="xml"></iframe>  
  56. <div id="res"></div>  
  57. </body>  
  58. </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源文件如下:

  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <exam>  
  3.     <no id="1">  
  4.         <question1>我喜歡與歷史學家交往<q>ceshi</q></question1>  
  5.         <question2>我做事進度較慢,但確保成效</question2>  
  6.         <value>4</value>  
  7.     </no>  
  8.     <no id="2">  
  9.         <question1>我想要每個人都喜歡我</question1>  
  10.         <question2>我一貫努力工作</question2>  
  11.         <value>7</value>  
  12.     </no>  
  13.     <no id="3">  
  14.         <question1>我力爭第一</question1>  
  15.         <question2>我思考自身的長處</question2>  
  16.     </no>  
  17.     <no id="4">  
  18.         <question1>我思考有待改進之處</question1>  
  19.         <question2>我是一個偏重情感的人</question2>  
  20.     </no>  
  21.     <no id="5">  
  22.         <question1>我能夠接受多種類型的人</question1>  
  23.         <question2>我想念我的朋友</question2>  
  24.     </no>  
  25.     <no id="6">  
  26.         <question1>與陌生人交談使我興奮</question1>  
  27.         <question2>我認為自己很能干</question2>  
  28.     </no>  
  29.     <no id="7">  
  30.         <question1>我通過與新人建立聯系獲得滿足感</question1>  
  31.         <question2>競爭與挑戰讓我感到興奮</question2>  
  32.     </no>  
  33.       
  34.     <no id="8">  
  35.         <question1>成為他人的知己使我滿足</question1>  
  36.         <question2>我信守自己的價值觀</question2>  
  37.     </no>  
  38. </exam>  
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <exam>  
  3.     <no id="1">  
  4.         <question1>我喜歡與歷史學家交往<q>ceshi</q></question1>  
  5.         <question2>我做事進度較慢,但確保成效</question2>  
  6.         <value>4</value>  
  7.     </no>  
  8.     <no id="2">  
  9.         <question1>我想要每個人都喜歡我</question1>  
  10.         <question2>我一貫努力工作</question2>  
  11.         <value>7</value>  
  12.     </no>  
  13.     <no id="3">  
  14.         <question1>我力爭第一</question1>  
  15.         <question2>我思考自身的長處</question2>  
  16.     </no>  
  17.     <no id="4">  
  18.         <question1>我思考有待改進之處</question1>  
  19.         <question2>我是一個偏重情感的人</question2>  
  20.     </no>  
  21.     <no id="5">  
  22.         <question1>我能夠接受多種類型的人</question1>  
  23.         <question2>我想念我的朋友</question2>  
  24.     </no>  
  25.     <no id="6">  
  26.         <question1>與陌生人交談使我興奮</question1>  
  27.         <question2>我認為自己很能干</question2>  
  28.     </no>  
  29.     <no id="7">  
  30.         <question1>我通過與新人建立聯系獲得滿足感</question1>  
  31.         <question2>競爭與挑戰讓我感到興奮</question2>  
  32.     </no>  
  33.     <no id="8">  
  34.         <question1>成為他人的知己使我滿足</question1>  
  35.         <question2>我信守自己的價值觀</question2>  
  36.     </no>  
  37. </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節點所包含的文本
如果要下載測試文件可到 http://leeyee.javaeye.com/blog/685352 進行下載


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM