自制XML解析器源码分析
自制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解析器源码分析相关推荐
- wireshark协议解析器 源码分析 封装调用
源码分析 Wireshark启动时,所有解析器进行初始化和注册.要注册的信息包括协议名称.各个字段的信息.过滤用的关键字.要关联的下层协议与端口(handoff)等.在解析过程,每个解析器负责解析自己 ...
- mysql源码如何解析where字句_MySQL解析器源码分析--对select语句中子查询处理逻辑的分析(一)...
背景 一个最简单的select语句包含select子句.from子句.where子句等,这些子句都不包含子查询(subselect),也没有union操作.而复杂的select语句包含select子句 ...
- 图解VC++版PE文件解析器源码分析
该源码下载自 http://download.csdn.net/download/witch_soya/4979587 1 Understand 分析的图表 2 PE结构解析的主要代码简要分析 首先看 ...
- 一步步实现windows版ijkplayer系列文章之二——Ijkplayer播放器源码分析之音视频输出——视频篇...
一步步实现windows版ijkplayer系列文章之一--Windows10平台编译ffmpeg 4.0.2,生成ffplay 一步步实现windows版ijkplayer系列文章之二--Ijkpl ...
- THOR:MindSpore 自研高阶优化器源码分析和实践应用
摘要:这篇文章跟大家分享下THOR的实践应用.THOR算法的部分内容当前已经在MindSpore中开源 本文分享自华为云社区<MindSpore 自研高阶优化器源码分析和实践应用>,原文作 ...
- Java定时任务(一) Timer及TimerTask的案例解析及源码分析
Java定时任务(一) Timer及TimerTask的案例解析及源码分析 一.概述: 定时任务这个概念在Java的学习以及项目的开发中并不陌生,应用场景也是多种多样.比如我们会注意到12306网站 ...
- 一步步实现windows版ijkplayer系列文章之三——Ijkplayer播放器源码分析之音视频输出——音频篇
https://www.cnblogs.com/harlanc/p/9693983.html 目录 OpenSL ES & AudioTrack 源码分析 创建播放器音频输出对象 配置并创建音 ...
- Android端视频播放器源码分析
这篇文章主要是分析视频播放器的实现代码.代码地址:查看 整体设计框架 我们播放本地的视频文件需要封装出一个输入模块: 输入模块要开启一个线程来处理解封装和解码,把得到的裸数据放到音频和视频的队列中. ...
- python程序代码解析_Python源码分析3 – 词法分析器PyTokenizer
Introduction 上次我们分析了Python中执行程序可分为5个步骤: Tokenizer进行词法分析,把源程序分解为Token Parser根据Token创建CST CST被转换为AST A ...
- JavaScript语言精粹JSON解析器源码阅读
1 // 这是一个用JavaScript编写JSON解析器的实现方案: 2 var jsonParser = (function() { 3 // 这是一个能把JSON文本解析成JavaScript数 ...
最新文章
- 微服务实践分享(8) 控制调用中心
- python获取输入法状态_Python学习中常见的错误
- 【算法笔记】重刷PAT 题解合集
- Power Automate生产现场实例分享回顾
- objective-c 语法快速过(4)
- Recurrent Neural Network系列1--RNN(循环神经网络)概述
- 199-Pycharm相关
- pb实现简单计算器的思想_人教版初中数学七年级下册 用计算器求算数平方根、用有理数估计算数平方根的大小公开课优质课课件教案视频...
- 再造轮子之网易彩票-第一季(IOS 篇 by sixleaves)
- Unity3D Asset文件导出3DMax 可编辑格式
- 点餐小程序源码|PHP微信点餐小程序
- selenium自动化入门之实现163邮箱发送邮件
- 串口调试助手linux设备串口,linux下安装串口调试助手
- PS制作logo图片
- 结构作为函数参数要注意什么_为什么要重视间架结构
- Re: Object Oriented
- 常说的“四层”和“七层”是什么
- [406]百度云下载不限速
- centos7.4和ubuntu16.0.4常用命令
- SpringCloud之分布式配置中心组件Config从远程Git仓库读取配置文件