通过javascript+DOM方式遍历XML节点(一)[原创] 
2007/7/26 22:14:37
阅读全文(7918) | 回复(1) | 编辑 | 精华
通过javascript+DOM方式遍历XML节点(一) ******************************************版权作者:Qr **成文时间:2007/07/18 22:25:00 **原创站点:http://Qr.blogger.org.cn **版权声明:转载请保留版权信息 ****************************************** 写在前面:曾经有位论坛上的网友问我,为什么不写些理论教程让大家学习和参考?我笑说工作太忙,抽不出时间。的确工作还是比较忙的,但只是其中一个理由。还有一个就是,网络上各种教程满天飞,自己也找不到一个好的切入点。前些日子,一个网友发贴子问遍历XML节点的问题(相关文章:一个遍历XML所有节点的递归代码[javascript+DOM方式]),我随手写了一段递归代码给对方。代码没什么过人之处,纯粹就事论事,针对那个特定的XML文档来写的,可是站长Collin还是给我加精了,惭愧。闲着没事,把相关代码继续完善一下,写成通用程序,也不辜负站长Collin给我前面那段代码加精。整理整理,形成了好几个版本的代码,看情况吧,也许会形成一个系列,也不是什么教程,贴上来看大家有没有不同的实现方法,与大家共勉吧! 简单说明:至今没想过js+DOM方式遍历XML节点有什么意义,为了体现遍历的效果,干脆就把遍历的结果以IE浏览XML的方式输出,当然只是纯粹进行格式化而已,因为涉及到MSXML版本的问题,序言和处理指令这一块没有考虑。 编程思路:自上而下、由外到内进行递归(正向),遇到子节点即继续遍历其下级节点,直到子节点为文本节点,然后后退,再次运用递归(反向),返回到其任意祖先级节点的相邻且含有子节点的兄弟节点,再递归(正向)遍历其下级节点,直到完成所有节点的遍历。 JAVASCRIPT实现: <script language="javascript"> /* ****************************************************** *代码:Qr http://Qr.blogger.org.cn * *时间:2007/07/15 21:36:00 * *功能:遍历XML的所有节点,仿IE浏览XML方式输出 * *类型:支持TEXT、CDATA、COMMENT、ELEMENT节点* ****************************************************** */ var xml = null , format = "" , fo = " " ; function main(){ createXmlDom("parser.xml"); Recursion(xml.documentElement); } function createXmlDom(xmlUrl){//这里大家可以自己处理一下,以适应不同浏览器 xml = new ActiveXObject("Msxml2.DOMDocument"); xml.async=false; xml.load(xmlUrl); } function Recursion(o) { if(typeof(o)=="number")return; if(o.nodeType==3 || o.nodeType==4 || o.nodeType==8){ switch(o.nodeType){ case 3://[TEXT型节点] if(o.nextSibling || o.previousSibling)document.write("<br>"+format); document.write(o.nodeValue); //针对混合节点的末节点为文本节点的情况 if(!o.nextSibling && o.previousSibling){ document.write("<br>"+format.substr(0,format.length-24)); } break; case 4://[CDATA型节点] document.write("<br>"+format+"<![CDATA["+o.nodeValue+"]]>");//.replace("<","<") break; case 8://[COMMENT型节点] document.write("<br>"+format+"<!--"+o.nodeValue+"-->");//.replace("<","<") break; } if(o.nextSibling){ //#有同级兄弟元素节点#// return arguments.callee(o.nextSibling); }else{ //#返回上级相邻未解析节点#// return arguments.callee(N2NP(o.parentNode)); //开始因为N2NP这个函数有问题,所以用try{}catch(e){} //try{return arguments.callee(N2NP(o.parentNode));}catch(e){document.write ("<b><i>err:"+e+"</i></b>")}; } } if(!o.hasChildNodes()){//[空无素(ELEMENT)或仅含属性(ATTRIBUTE)] if(o!=xml.documentElement)document.write("<br>"); if(o.nodeType==1)document.write(format+"<"+o.nodeName); if(o.attributes.length>0)attrparser(o); document.write("/>"); if(o.nextSibling){ //#有同级兄弟元素节点#// return arguments.callee(o.nextSibling); }else{ //针对混合节点的末节点为空元素的情况 if(o.previousSibling)document.write("<br>"+format.substr(0,format.length-24)); //#返回上级相邻未解析节点#// return arguments.callee(N2NP(o.parentNode)); //开始因为N2NP这个函数有问题,所以用try{}catch(e){} //try{return arguments.callee(N2NP(o.parentNode));}catch(e){document.write("<b>err:"+e+"</b>")}; } } if(o.hasChildNodes()){//有子节点,包括:TEXT、CDATA、COMMENT、ELEMENT if(o.nodeName!=xml.documentElement.nodeName)document.write("<br>"); if(o.nodeType==1)document.write(format+"<"+o.nodeName); if(o.attributes.length>0)attrparser(o); document.write(">"); if(o.hasChildNodes()){//#有下级元素节点#// format += fo; return arguments.callee(o.firstChild); }else{ if(o.nextSibling){//#有同级兄弟元素节点#// return arguments.callee(o.nextSibling); } } } } function N2NP(p){//alert(p.nodeName+":"+p.nodeValue) if(p.nextSibling){ format = format.substr(0,format.length-24); //输出关闭标记 if(p.nodeType==1 && p.firstChild.nodeType==3)document.write("</"+p.nodeName+">"); if(p.nodeType==1 && p.firstChild.nodeType!=3)document.write("<br>"+format+"</"+p.nodeName+">"); return p.nextSibling;//返回相邻节点 }else{ format = format.substr(0,format.length-24); //输出关闭标记 if(p.parentNode && p.firstChild.nodeType==3)document.write("</"+p.nodeName+">"); if(p.parentNode && p.firstChild.nodeType!=3)document.write("<br>"+format+"</"+p.nodeName+">"); if(p==xml.documentElement){return 0;}else{//如果不进行判断,函数将返回#document,导致错情 return arguments.callee(p.parentNode);//#返回上级相邻未解析元素节点#// } } } function attrparser(o){//遍历节点元素 if(o.attributes){ var attr = o.attributes; for(i=0;i<attr.length;i++){ document.write(" "+attr[i].nodeName+'="'+attr[i].firstChild.nodeValue+'"'); } } } main(); </script> 测试用XML文档:实际上这个文档是写后面两个版本的代码时,根据调试的情况,假设不同的情形,临时添加节点形成的,非常零乱,但是谁能保证某些客户不会提出这样的刁钻要求呢?!懒得重新设计所谓典型的XML文档,干脆就把这个文档贴出来当典型吧:-)后续文章还是继续延用这个测试文档。parser.xml:<?xml version="1.0" encoding="gb2312" ?> <root> <!--COMMENT和CDATASection作为首个子节点在此出现没问题--> <elements attribute="来个无文本节点试试,哈哈,没问题"/> <elements> <element attribute1="随便啦" attribute2="再多一个又如何">只有一行文本的节点</element> <CDATASection> <![CDATA[CDATASection和COMMENT相邻出错?※搞掂※]]> <!--COMMENT和CDATASection相邻出错?※搞掂※--> </CDATASection> <COMMENT> <!--针对以上相邻出错的问题将两个类型节点换个次序--> <![CDATA[已经没有问题啦]]> </COMMENT> <CDATASection> <![CDATA[CDATASection嵌套在一个空节点内]]> </CDATASection> <elem1> <elem2> 既然已经解决,再加一个文本节点再这里试试! <elem3> <![CDATA[CDATASection嵌套在多级空节点内出错?※搞掂※]]> </elem3> 再再加一个文本节点再这里试试,没问题! </elem2> </elem1> <![CDATA[CDATASection嵌套在两级以上节点均已调试通过]]> <COMMENT> <!--COMMENT嵌套在一级空节点中--> </COMMENT> <COMMENT> <!--再加一个在此处--> <comment> <!--COMMENT嵌套在多级空节点中--> </comment> </COMMENT> <!--COMMENT嵌套在两级以上节点均已调试通过--> <!--COMMENT--> <![CDATA[CDATASection]]> <ELEMENT ATTRIBUTE="属性值">元素文本</ELEMENT> <![CDATA[CDATASection混杂在节点中]]> <中文节点>已经定义了encoding,没问题的</中文节点> <!--COMMENT混杂在节点中--> <ELEM>ELEM1</ELEM> <ELEM>ELEM2</ELEM> <ELEM>ELEM3</ELEM> <EMPTY> <empty> <noValue/> </empty> </EMPTY> <!--两级及以上空节点嵌套已通过--> <ELEMENT> <element 属性="attribute" 还是属性="ATTRIBUTE">两级节点嵌套,含文本</element> </ELEMENT> <ELEMENT> <element> <elem>多级节点嵌套,含文本</elem> <!--COMMENT或CDATASection在末尾有问题!※搞掂※--> </element> </ELEMENT> <interfusion> <!----> 混合节点调试通过 <element> element value <empty/> </element> 空元素调试通过 <!--COMMENT--> <![CDATA[CDATASection]]> Text <ELEMENT>ELEMENT VALUE</ELEMENT> TEXT <![CDATA[COMMENT或CDATASection在末尾有问题!※搞掂※]]> </interfusion> </elements> <!--COMMENT或CDATASection作为根节点的末子节点有问题!※搞掂※--> <![CDATA[你会不会设计如此结构的XML文档,反正偶不会,看着就头痛□]]></root> 自我点评: 代码好坏不必说,我自己清楚。相信大家对DOM的性能应该是比较清楚的,它不能处理体积过于庞大的XML文档,这是一个现实。当然另一个实现是电脑的性能了,CPU性能越高、内存越大,处理能力就越强。 但以上自定义函数Recursion()所使用的javascript递归却更加严重影响了遍历和性能,所以,当如果XML文档体积过大的时候(当然这个体积远比不使用递归的小很多),就不能完整将XML节点遍历出来了。 下一篇将摒弃javascript的递归来实现XML节点的遍历。 相关文章:一个遍历XML所有节点的递归代码[javascript+DOM方式] 待续......
Posted by Qr on 2007/7/26 22:14:37
回复:通过javascript+DOM方式遍历XML节点(一)[原创]
2007/7/19 0:21:52
个人主页 | 引用回复 | 主人回复 | 返回 | 编辑 | 删除
红色有点刺眼。。
Posted by 徐涵(Han Xu) on 2007/7/19 0:21:52
发表评论: |