自制XML解析器源码分析

首先,我们确定一下需求:

(1)我们希望它能把XML字符串解析成JSON对象。

(2)至少能兼容FireFox和IE。

(3)这个工具类最好是单例的。

代码:

/**

* 把XML解析成JSON对象

* 既可以直接解析字符串拼接成的XML

* 也可以解析通过Ajax请求获得的XML文件对象

* 主要兼容:IE、FireFox、Opera,其他浏览器中不能运行

* @author 大漠穷秋

* @since 2010-12-24

* @ver 1.0

*/

XmlParser=(function(){

functioncreateXmlDocument(){

vardoc=null;

if(Ext.isIE){

var docIDs = [

"Msxml2.DOMDocument.6.0",

"Msxml2.DOMDocument.5.0",

"Msxml2.DOMDocument.4.0",

"Msxml2.DOMDocument.3.0",

"MSXML2.DOMDocument",

"MSXML.DOMDocument"

];

for(var i=0;i<docIDs.length;i++){

//尝试为IE创建XMLDocument对象

try{

doc=newActiveXObject(docIDs[i]);

return doc

}catch(e){}

}

throw new Error("无法为你的浏览器创建XMLDocument对象。");

}else{//FireFox,Opera,Safari,Chrome

doc= document.implementation.createDocument ("","",null);

}

returndoc;

};

this.stack=[];

function_preParse(xmlNode){

if(xmlNode.childNodes){

for(vari=0;i<xmlNode.childNodes.length;i++){

varnode=xmlNode.childNodes[i];

varnodeType=node.nodeType;

if(nodeType==1){        //复合节点

varobj={};

obj.name=node.tagName;

obj.children=[];

stack.push(obj);

_preParse(node);

if(nodeType==1){

vartop=stack.pop();

if(stack.length==0){

returntop;

}

vartop2=stack[stack.length-1];

top2.children.push(top);

}

}elseif(nodeType==3){   //文本节点

//过滤掉空行、回车、制表符

vartext=null;

if(Ext.isIE){

text=node.text;

}else{

text=node.textContent;

}

varresult=text.replace(/(\r|\n|\t|\s)/g, '');

if(result){

vartop=stack[stack.length-1];

deletetop.children;

top.value=result;

}

}

}

}

}

this.xmlDoc=createXmlDocument();

functionxmlToJSON(xmlNode){

stack=[];

varresult=_preParse(xmlNode);

returnresult;

};

return {

/**

* 解析xmlObj并返回JSON对象

*/

parse:function(xmlObj){

if(!xmlObj){

returnnull;

}

/**

* 直接解析字符串拼接成的XML

* 尚未实现

*/

if(Ext.type(xmlObj)=='string'){

thrownew Error("直接解析字符串的功能尚未实现。");

returnnull;

}

returnxmlToJSON(xmlObj);

},

/**

* 解析Ajax加载的XML文件

*/

parseResponse:function(response){

if(!response||!response.responseXML){

thrownew Error("无法读取响应数据,response为null或没有xml
                    数据。");

returnnull;

}

returnthis.parse(response.responseXML);

},

/**

* 直接加载远程XML文件

* 貌似有缓存问题

*/

loadXml:function(filePath,fn){

if(Ext.isIE){

xmlDoc.onreadystatechange=function(){

if(xmlDoc.readyState==4){//XML文档已经加载完毕

fn(xmlDoc);

}

}

}else{

xmlDoc.οnlοad=fn.createCallback(xmlDoc);

}

xmlDoc.load(filePath);

},

/**

* 获取当前正在解析的XMLDocument对象

*/

getDocObj:function(){

returnxmlDoc;

}

}

})();

源码解析:

约定一些解析规则:

(1)XML的标签名变成对象的name属性。

比如:

<name>大漠穷秋1</name>

会被解析成:

{name:'name',value:'大漠穷秋1'}

(2)如果标签存在子节点,将自动创建一个children属性,用来存储子对象。

比如:

<skill>

<name>Java</name>

<year>4</year>

</skill>

会被解析成:

{name:'skill',children:[

        {name:'name',value:'Java'},

        {name:'year',value:'4'}

]}

在XmlParser中,核心工具函数是createXmlDocument()、_preParse()这两个。

createXmlDocument看起来比较烦琐,其实没有技术含量,主要完成根据不同浏览器创建出XmlDocument对象的任务。与Ajax中的XmlHttpRequest对象类似,XmlDocument这个对象依赖于具体浏览器的实现。在不同的浏览器中,创建XmlDocument的方式不同,并且最终暴露出来的属性和方法都有很大的差别。

作为Ext的超级粉丝,我们见识了大量的JS技巧和框架设计思想,想象一下,你也是Ext框架开发团队中的一员,你会如何去设计这个解析工具?秉承Ext一贯的思路和手法,必须先把浏览器的差异屏蔽掉,然后对上层调用代码暴露一组通用的编程接口,这就是createXmlDocument这个函数存在的理由。

XML是一种“树形”的结构,它拥有唯一的根节点,然后标签可以层层嵌套。只要注意标签的配对、关闭及不能出现特殊的符号等,其他并没有特别的限制。那么在解析过程中必然会涉及树节点的遍历问题,这里使用的解析方法是:前序遍历栈存储节点递归3个手段结合。

在这个过程中,最核心的一个手法是使用一个数组做栈,在递归的过程用来存储访问过的节点。当发现某个节点还有子节点的时候,就把这个节点做成这样一个对象入栈:{name:'节点标签名',value:'',children[]},然后继续访问它的第一个孩子节点。当发现某个节点已经是简单节点(没有子节点),则把它“做成”JSON对象,然后弹出栈顶元素,把简单节点对应的JSON对象插入弹出元素的children数组中去。

核心的思路如上所述,如图7-28所示,但是纯文字描述必然比较抽象,请读者自行使用Firebug跟踪以上过程。

——本段文字节选自《EXT江湖》

图书详细信息:http://blog.csdn.net/broadview2006/article/details/7211734

自制XML解析器源码分析相关推荐

  1. wireshark协议解析器 源码分析 封装调用

    源码分析 Wireshark启动时,所有解析器进行初始化和注册.要注册的信息包括协议名称.各个字段的信息.过滤用的关键字.要关联的下层协议与端口(handoff)等.在解析过程,每个解析器负责解析自己 ...

  2. mysql源码如何解析where字句_MySQL解析器源码分析--对select语句中子查询处理逻辑的分析(一)...

    背景 一个最简单的select语句包含select子句.from子句.where子句等,这些子句都不包含子查询(subselect),也没有union操作.而复杂的select语句包含select子句 ...

  3. 图解VC++版PE文件解析器源码分析

    该源码下载自 http://download.csdn.net/download/witch_soya/4979587 1 Understand 分析的图表 2 PE结构解析的主要代码简要分析 首先看 ...

  4. 一步步实现windows版ijkplayer系列文章之二——Ijkplayer播放器源码分析之音视频输出——视频篇...

    一步步实现windows版ijkplayer系列文章之一--Windows10平台编译ffmpeg 4.0.2,生成ffplay 一步步实现windows版ijkplayer系列文章之二--Ijkpl ...

  5. THOR:MindSpore 自研高阶优化器源码分析和实践应用

    摘要:这篇文章跟大家分享下THOR的实践应用.THOR算法的部分内容当前已经在MindSpore中开源 本文分享自华为云社区<MindSpore 自研高阶优化器源码分析和实践应用>,原文作 ...

  6. Java定时任务(一) Timer及TimerTask的案例解析及源码分析

    Java定时任务(一)  Timer及TimerTask的案例解析及源码分析 一.概述: 定时任务这个概念在Java的学习以及项目的开发中并不陌生,应用场景也是多种多样.比如我们会注意到12306网站 ...

  7. 一步步实现windows版ijkplayer系列文章之三——Ijkplayer播放器源码分析之音视频输出——音频篇

    https://www.cnblogs.com/harlanc/p/9693983.html 目录 OpenSL ES & AudioTrack 源码分析 创建播放器音频输出对象 配置并创建音 ...

  8. Android端视频播放器源码分析

    这篇文章主要是分析视频播放器的实现代码.代码地址:查看 整体设计框架 我们播放本地的视频文件需要封装出一个输入模块: 输入模块要开启一个线程来处理解封装和解码,把得到的裸数据放到音频和视频的队列中. ...

  9. python程序代码解析_Python源码分析3 – 词法分析器PyTokenizer

    Introduction 上次我们分析了Python中执行程序可分为5个步骤: Tokenizer进行词法分析,把源程序分解为Token Parser根据Token创建CST CST被转换为AST A ...

  10. JavaScript语言精粹JSON解析器源码阅读

    1 // 这是一个用JavaScript编写JSON解析器的实现方案: 2 var jsonParser = (function() { 3 // 这是一个能把JSON文本解析成JavaScript数 ...

最新文章

  1. 微服务实践分享(8) 控制调用中心
  2. python获取输入法状态_Python学习中常见的错误
  3. 【算法笔记】重刷PAT 题解合集
  4. Power Automate生产现场实例分享回顾
  5. objective-c 语法快速过(4)
  6. Recurrent Neural Network系列1--RNN(循环神经网络)概述
  7. 199-Pycharm相关
  8. pb实现简单计算器的思想_人教版初中数学七年级下册 用计算器求算数平方根、用有理数估计算数平方根的大小公开课优质课课件教案视频...
  9. 再造轮子之网易彩票-第一季(IOS 篇 by sixleaves)
  10. Unity3D Asset文件导出3DMax 可编辑格式
  11. 点餐小程序源码­|PHP微信点餐小程序
  12. selenium自动化入门之实现163邮箱发送邮件
  13. 串口调试助手linux设备串口,linux下安装串口调试助手
  14. PS制作logo图片
  15. 结构作为函数参数要注意什么_为什么要重视间架结构
  16. Re: Object Oriented
  17. 常说的“四层”和“七层”是什么
  18. [406]百度云下载不限速
  19. centos7.4和ubuntu16.0.4常用命令
  20. SpringCloud之分布式配置中心组件Config从远程Git仓库读取配置文件

热门文章

  1. VSCode中使用vue项目ESlint验证配置
  2. Windows 10下使用Xshell5连接虚拟机的ubuntu18系统
  3. 两种方法递归斐波那契数列
  4. Linux内核分析学习心得
  5. C++ json解析
  6. Redis学习笔记(二) Redis 数据类型
  7. Uva(10986)
  8. 【推荐】会被快速否决的9种求职者.
  9. NeurlPS2021 | 视觉语言导航的课程学习
  10. 【过拟合】防止模型过拟合的必备方法!