`
iunknown
  • 浏览: 410161 次
社区版块
存档分类
最新评论

spxml:使用 state pattern 实现 xml pull/dom parser

阅读更多
spxml 是一个实现了 pull 和 dom 两种解释模型的 xml 解释器。
spxml 使用 c++ 实现,除系统库之外,不依赖第三方库,目前实现了以下功能:
1.实现了 xml pull parser 的功能;
2.基于 xml pull parser 构造一个 dom tree;
3.能够对 dom tree 进行修改;
4.能把 dom tree 重新序列化为一个字符流;
5.处于底层的 xml pull parser 是一个面向流的解释器,用户不需要一次把一个完整的 xml 字符流传递给 spxml ,极端情况下,可以每次只传入一个字符。解释到一个文档结束时,自动生成 EndDocument 事件;
6.xml dom parser 同样继承了面向流的特性;
7.使用 xmlbench 框架做压力测试,性能与 expat 相当接近。


源代码下载:
http://spxml.googlecode.com/files/spxml-0.3.src.tar.gz

一些设计思路的说明:

最近在使用 cpp 做 xmlrpc 相关的内容,顺便看了一下几个 xmlrpc 的实现,连带看了一下 expat 的实现。
发现 expat 的接口非常的精简,不过实现的代码比较长,比较难读。
看完之后,有空的时候就在思考有什么办法可以简化 xml parser 的实现。
想了几天之后,想到一个方法:expat 里面有很多的 switch case 结构,要简化这些 switch ,最好使用 state pattern 。

具体的想法如下:
<<1>> 设计一个 XmlReader 类,作为 state pattern 中的 State 类。
  XmlReader 的多个子类作为 state pattern 的 ConcreteState 类,
  每个 reader 代表 xml parser 的一个状态。
  比如有:XmlDocDeclReader,XmlStartTagReader,XmlEndTagReader,XmlCDataReader,
  XmlCommentReader,XmlDocTypeReader等等。
<<2>> xml parser 本身作为 state pattern 中的 Context 类。

这样设计的好处(为描述方便,称这个 xml parser 为 spxml):
<<1>> 每个 XmlReader 识别特定的开始符和结束符,把属于它自己的字符保存下来。
  在遇到它的结束符之后,设置 spxml 的后继 XmlReader。
<<2>> 每个 XmlReader 在读取到结束符之后,把保存下来的字符串转换成 parser 相应的事件。
  比如:对于 XmlStartTagReader 来说,如果是一个 pull-model 的 xml parser,
  将产生一个 START_TAG event;如果是一个 sax-model 的 xml parser,那么将产生
  StartElement event。
<<3>> 这样把 xml 的各个部分的处理分散到了不同的类里面,每个类只处理一类情况,
  这就使得 spxml 的实现从整体上简化了。
<<4>> spxml 像 expat 一样,是一个面向流的解释器。
  使用者可以把任意大小的 xml 片断(从一个字节到完整的 xml document)传递给 spxml 进行解释。
  expat 需要由使用者指出 xml document 何时结束;相反,spxml 不需要由调用者指定 xml document
  何时结束,在解释完 root element 之后,spxml 将返回 END_DOCUMENT 事件。
  因此 spxml 适合使用在类似 jabber 这类协议的通讯中。
  因为 jabber 的传输协议中,任意两个请求包中是没有明显的分隔符的,每个请求只是一个完整的 xml element。

为了验证一下自己的想法,趁这段时间休假,花了几天时间实现了一下,初步看起来还是不错的。目前针对简单的 xml 实现了 xml pull parser 和 xml dom parser,足够用来处理 xmlrpc。
分享到:
评论
3 楼 spinach 2007-03-22  
学习~
2 楼 iunknown 2007-01-19  
对 spxml 和 expat 做了一下性能测试。
以 [url] http://xmlbench.sourceforge.net/ [/url] 作为测试框架。

测试环境是在 vmware 上,并且机器性能不好,只能测试 4k 和 256k 的样本。

由于 spxml 没有 sax 接口,而 expat 只有 sax 接口,所以无法直接进行对比,只能借助 Sablot ,双方对 dom 进行测试。

采用的版本:expat-2.0.0  + Sablot-1.0.3

--->Running <expat-sablotron-dom> benchmarks:
-> xmlgen 4 KB
Initialisation time 0.106 + 0.613(6.48%) ms, Parsing Time 1.620(2.45%) ms
-> xmlgen 256 KB
Initialisation time 0.137 + 1.121(114.60%) ms, Parsing Time 126.102(1.02%) ms

--->Running <spxml-dom> benchmarks:
-> xmlgen 4 KB
Initialisation time 0.022 + 0.433(19.64%) ms, Parsing Time 2.534(3.36%) ms
-> xmlgen 256 KB
Initialisation time 0.033 + 0.000(0.00%) ms, Parsing Time 3449.899(0.08%) ms

在 256k 的时候,spxml 实在太糟糕了。初步猜想是因为 spxml 是基于 pull 接口来构造 dom 的,pull 接口返回的是一个 event object, 然后在 event object 的基础上,再封装了一个 node object。 而 expat + sablot 直接通过 sax 接口构造 dom,少了一次的 object 构造。

做了这些测试之后,重新 review 了一下 spxml 的代码,希望可以通过一些简单的改动,减少 object 的构造。之后对 StartTagReader 和 DomParser 做了一些改动,然后重新测试。

--->Running <spxml-dom> benchmarks:
-> xmlgen 4 KB
Initialisation time 0.002 + 0.388(16.89%) ms, Parsing Time 1.601(4.09%) ms
-> xmlgen 256 KB
Initialisation time 0.002 + 5.474(30.01%) ms, Parsing Time 164.281(1.00%) ms

看来这次的改动还是比较成功的,大幅缩短了运行时间。

详细考察改进的细节,发现最耗时间的地方是在 ArrayList 的操作上。
这个 ArrayList 是仿照 java.util.ArrayList 实现的一个列表。
之所以需要 ArrayList 操作,是在 PULL parser 的实现中,遇到一个两难的选择:
pull parser 要支持面向流的功能,有一个 append 方法;
pull parser 对外提供的主要方法是 getNext 方法,用来获得当前已经生成的 xml event。

问题在于:
1.在 append 方法中做实际的 xml 解释,把解释得到的 xml event 保存到一个 ArrayList 中,getNext 方法只是从 ArrayList 中取的 xml event;
2.在 append 中只是把字符流保存起来,在 getNext 中才进行解释。

目前的实现是采用方法一。原因是方法二导致额外的内存复制操作。
目前改进了 ArrayList 的操作,所以在性能上有很大的提高。
1 楼 Arath 2007-01-18  
实现完全不是问题.
不过...如果我记得没有错expat是纯C的代码,所以很多地方不得不如此实现,而且大量使用了C中的一些小技巧,所以可读性降低.
但是它的功能很强大,速度方面也很好,而且因为是C的,所以移植性很好,可以很容易用于很多不支持C++开发的平台。

相关推荐

    DOMParser解析xml

    DOMParser接口提供了解析XML字符串并创建DOM文档的方法,以便于开发者可以使用DOM API来查询、修改或操作XML数据。 以下是对"DOMParser解析XML"这一主题的详细说明: 1. **DOMParser的基本使用**: 使用DOMParser...

    XMLParser iphone

    XMLParser在iOS开发中是一种常用的解析XML数据的工具,它允许开发者将XML文件转换为可操作的数据结构,便于在iPhone应用程序中使用。XML(Extensible Markup Language)是一种标记语言,常用于存储和传输结构化数据...

    perl的xml::simple解析文件

    Perl中的XML::Simple模块是Perl社区广泛使用的XML解析器,尤其适合处理小型或结构简单的XML文档。这个模块的名称虽然包含“Simple”,但它实际上提供了一种简洁的接口,用于将XML数据转换为Perl数据结构,反之亦然。...

    pull-parser-2.jar 工具類

    《pull-parser-2.jar工具类:Android开发中的XML与JSON解析利器》 在移动应用开发领域,尤其是在Android平台上,高效地处理XML和JSON数据是必不可少的技能。`pull-parser-2.jar`工具类库就是这样一个专门针对XML和...

    dom4j pull parser

    在实际应用中,结合DOM4J的Pull Parser,你可以实现诸如XML数据的增量读取、动态解析XML配置文件、以及在移动设备或嵌入式系统上高效处理XML等任务。由于DOM4J具有丰富的API和广泛的社区支持,因此即使在较旧的版本...

    DBMS_XMLDOM DBMS_XMLPARSER DBMS_XMLQUERY 文档

    Oracle数据库系统提供了强大的XML处理能力,这主要体现在其内置的几个PL/SQL包上,如DBMS_XMLDOM、DBMS_XMLPARSER和DBMS_XMLQUERY。这些包为开发者提供了处理XML文档的一整套工具,使得在数据库环境中进行XML数据的...

    XMLParser(XML解析代码 C++版)

    XMLParser是一种用于解析XML文档的C++实现,它旨在提供简单、小巧且稳定的解决方案,以处理XML数据。XML,即可扩展标记语言,是用于存储和传输数据的标准格式,广泛应用于配置文件、数据交换和文档结构化等领域。XML...

    SAX,PULL,DOM解析XML

    在处理XML文档时,有三种主要的解析方式:SAX(Simple API for XML)、PULL(Pull Parser)和DOM(Document Object Model)。下面将详细解释这三种解析方法及其特点。 1. SAX(Simple API for XML) SAX是一种基于...

    使用sax,pull,dom4j解析XML

    在Java中,有三种主要的解析XML的方式:SAX(Simple API for XML)、Pull解析器和DOM4J。下面将详细介绍这三种方法以及它们在Eclipse 4.8和Java 1.8环境下的使用。 1. **SAX解析器** SAX是一种基于事件驱动的解析...

    PullParser2_1_7.tgz_PullParser2_1_7_xml parser_xml x_xml解析器

    Pull解析器特别适合移动设备和资源有限的环境,因为它不需要DOM(Document Object Model)整个树在内存中,而是按需处理XML事件,从而降低了内存使用。 PullParser2_1_7可能提供了以下功能: 1. 解析XML文档的开始...

    微信小程序解析xml的js

    在`dom-parser.js`中,我们可以创建一个`DOMParser`对象,然后使用`parseFromString()`方法将XML字符串转化为DOM对象,例如: ```javascript const DOMParser = require('./dom-parser.js'); const parser = new ...

    html-dom-parser:HTML到DOM解析器

    html-dom-parser 在服务器(Node.js)和客户端(浏览器)上均可使用HTML到DOM解析器: HTMLDOMParser(string[, options])解析器将HTML字符串转换为描述DOM树JavaScript对象。例子const parse = require ( '...

    pullparser的jar包.rar

    与DOM解析器不同,PullParser不需要一次性加载整个XML文档到内存中,而是通过事件驱动的方式逐个处理XML元素,从而节省内存并提高性能。 Android中的PullParser实现主要依赖于`org.xmlpull.v1.XmlPullParser`接口...

    XML解析DOM/SAX/PULL

    本文将详细介绍XML的三种解析方法:DOM(Document Object Model)、SAX(Simple API for XML)和PULL(Pull Parser),并提供相关的程序示例。 **DOM解析** DOM解析器将整个XML文档加载到内存中,创建一个树形结构...

    MSXML 4.0 sp2 parser sdk

    - 解析XML文档:通过DOMParser或SAXParser接口将XML数据加载到内存中,进行读取和操作。 - 验证XML文档:使用Schema对象和XML Schema Definition (XSD) 文件验证XML文档是否符合预定义的模式。 - XSLT转换:通过...

    dom4j_1_6_1 完整支持包下载

    pull-parser-2.1.10.jar relaxngDatatype-20030807.jar xml-apis-2.0.2.jar xpp3-1.1.3.3.jar xsdlib-20030807.jar 从GitHub上下载下来的,CSDN这资源分设置...恩,算了,没积分的自己去下载吧: ...

    DOMParser jar

    6. 查询和修改XML:DOM允许通过XPath表达式来查找特定的节点,或者直接通过节点的API进行修改。例如,查找名为"elementName"的元素: ```java NodeList nodeList = doc.getElementsByTagName("elementName"); for ...

    ua-parser-1.3.0.jar

    下载 ua-parser-master cd /app/ua-parser-master/java vi pom.xml &lt;version&gt;1.3.0&lt;/version&gt; 原来是&lt;version&gt;1.3.1-SNAPSHOT&lt;/version&gt; mvn package -DskipTests mvn install:install-file -Dfile="/app/ua-parser...

    mp4parser工具箱中isoparser和muxer的jar包

    mp4parser中的视频处理方法需要依靠该jar包才能运行,该jar包是基于mp4parser-mp4parser-project-1.9.27打包的。使用方法可以参考我的CSDN博文,地址是http://blog.csdn.net/u014691453/article/details/53256605

Global site tag (gtag.js) - Google Analytics