写在前面的
经常需要使用js来处理xml,在此做一总结.内容比较零散,但相对实用.
将xml文本转换为XMLDOM:
- function parseFromFile(addr){
- var xmlDoc;
- var sourceName = addr;
- if (window.XMLHttpRequest) { // FireFox
- var xmlDoc = document.implementation.createDocument("","",null);
- xmlDoc.async = false;
- xmlDoc.load(sourceName);
- }else if (window.ActiveXObject) { // IE
- try {
- xmlDoc = new ActiveXObject("Msxml2.XMLDOM");
- xmlDoc.async = false;
- xmlDoc.load(sourceName);
- } catch (e) {
- try {
- xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
- xmlDoc.async = false;
- xmlDoc.load(sourceName);
- } catch (e) {}
- }
- }
- return xmlDoc;
- }
- function parseFromString(_value){
- var xmlDoc = null;
- if(window.XMLHttpRequest){//firefox ..
- var oParser = new DOMParser();
- xmlDoc = oParser.parseFromString(_value,"text/xml");
- }else if(window.ActiveXObject){ //ie
- xmlDoc = new ActiveXObject( "Msxml2.DOMDocument");
- xmlDoc.loadXML(_value);
- }
- return xmlDoc;
- }
- function createXMLDOM(){
- var xmldom = null;
- if(window.XMLHttpRequest){//firefox ..
- xmldom = document.implementation.createDocument("","",null);
- }else if(window.ActiveXObject){ //ie
- xmldom = new ActiveXObject( "Msxml2.DOMDocument");
- }
- return xmldom;
- }
可以很方便的得到xml DOM文档的根节点
- var root = xmlDOM.documentElement;//xmlDOM为已得到的DOM文档
通过childNodes来取得子节点,但ie(trident核心)与firefox(gecko核心)对childNodes的解释有些许不同.经常在ie下工作正常的脚本,在其他浏览器中运行会出现错误,往往因为这个原因.
如xml文件data.xml内容为:
- <root>
- <test>testValue</test>
- </root>
var root = parseFromFile("test.xml");
ie中,root.childNodes.length == 3
firefox中,root.childNodes.length == 5
原因是firefox将一些无效的换行空格也作为文本节点进行计算
为保证在ie与ff中的一致操作,解决方法大致有以下两个:
1
- var nodes = root.getElementsByTagName("test");
- for(var i=0;i<nodes.length;i++){
- //TODO 对有效节点进行操作
- }
2
- for(var i=0;i<root.childNodes.length;i++){
- var node = root.childNodes[i];
- if(node.nodeType == 3)//无效的TEXT_NODE
- continue;
- if(node.nodeType == 1){//需要处理的ELEMENT_NODE
- //TODO 对有效节点进行操作
- }
- }
关于节点类型nodeType:
常用的nodeType大致三种:
1:ELEMENT_NODE
3:TEXT_NODE
4:CDATA_SECTION_NODE
接下来用一个例子来说明如何解析节点
data.xml内容
- <root>
- <test attr="attrValue">testValue</test>
- <test><![CDATA[测试cdata]]></test>
- <test></test>
- </root>
以下是解析过程
- var xmlDOM = parseFromFile("t.xml");
- var root = xmlDOM.documentElement;
- var tests = root.getElementsByTagName("test");
- //这里将不进行循环,仅对常用类型节点的解析进行说明
- //解析第一个test节点 (解析element_node类型)
- var test1 = tests[0];
- var test1_attr = test1.getAttribute("attr");//test1 属性
- alert(test1_attr);
- //注意:test1中的文本,本身是一个text_node
- var test1_value = test1.childNodes[0].nodeValue;
- alert(test1_value);
- //第二个节点 (解析cdata类型)
- var test2 = tests[1];
- var test2_value = test2.childNodes[0].nodeValue;
- alert(test2_value);
- //第三个节点 (与第一个节点有什么不同?)
- var test3 = tests[3];
- alert(test3.childNodes.length);//此时会发现test3的子节点数量为0,原因是当element_node节点下无文本时,将不会建立text_node节点
- var test3_value = "";
test1与test3虽然看起来结构相同,但由于其xml DOM的结构并不相同,因此处理的时候需要注意区分
一种办法是先判断节点的childNodes的长度,不为0时可使用test1的方式进行处理,否则使用test3的方式
另一种方法是通过判断浏览器,当为firefox时,使用test3.textContent属性进行存取,当为ie时,使用test3.text属性进行存取
以上两种方法都过于繁琐,当xml DOM节点比较多时,将产生比较多的冗余代码,那是否存在更为优雅的办法?答案是肯定的.
在页面载入时,在firefox中,通过Element的原型来创建text属性,从而达到在ie与firefox使用统一的text属性进行存取.
页面载入时的代码为:
- if(document.implementation && document.implementation.createDocument){//当浏览器为firefox时
- //alert("firefox...");
- Element.prototype.__defineGetter__(
- "text",
- function(){
- return this.textContent;
- }
- );
- Element.prototype.__defineSetter__(
- "text",
- function(sText){
- this.textContent=sText;
- }
- );
- }
使用js构造 xml DOM:
构造一个如data.xml内容的xml DOM
- var xmldom = createXMLDOM();
- var root = xmldom.createElement("root");
- var test1 = xmldom.createElement("test");
- test1.setAttribute("attr","testAttr");
- var test1Value = xmldom.createTextNode("testValue");
- root.appendChild(test1);
- test1.appendChild(test1Value);
- var test2 = xmldom.createElement("test");
- var testCDATA = xmldom.createCDATASection("<test>测试cdata</test>");
- root.appendChild(test2);
- test2.appendChild(testCDATA);
- var test3 = xmldom.createElement("test");
- root.appendChild(test3);
- alert(root.childNodes[0].text);
- alert(root.childNodes[1].text);
- alert(root.childNodes[2].text);
后记:
本文例程在ie6.0与firefox2.0中测试通过,对基于webkit核心的浏览器与opera在调用parseFromFile时尚有一些问题.