使用VTD-XML简化XML处理-克服DOM及SAX缺点的新选择

来源: http://www.matrix.org.cn/resource/article/44/44529_VTD-XML.html


使用VTD-XML简化XML处理-克服DOM及SAX缺点的新选择


概要


做 为下一代WEB应用的推动性技术,XML相当简单,易学易用。然而,当前的XML处理技术却非如此。Document Object Model和Simple API for XML都比较慢,低效,且不易于使用。VTD-XML,作为下一代的XML处理模型,提供超越DOM和SAX的广泛用途和更佳选择,不仅可以简化XML编 程,也使选择XML处理模型更加容易。这篇文章通过最近的基准测试数据和示例程序来突显它的关键性的技术优势,显示出VTD-XML将可能解决长期以来困 扰企业架构的,在DOM和SAX之间进行抉择的问题。

自从诞生以来的八年里,XML作为一个开放,半结构化的数据格式和WEB应用的数据交换工具,已取得了长足进步。由于它的简易性和良好的可读性,XML受到开发人员的热烈欢迎,并且已经成为了企业架构不可分割的一部分。

虽 然很难说清XML到底有多少种不同的应用,但至少有一点是肯定的:XML解析处理已成为各种工作的先决任务。实际上,决定使用哪种解析器也经常是企业开发 者在项目中必须首先解决的问题之一。长久以来,这其实就是在两种 XML处理模型之间做出选择:Document Object Model (DOM) 和 Simple API for XML (SAX)。

粗看之下,DOM和SAX各自的优缺点刚好形成互补。DOM使用内存保存对象结构;而SAX则基于事件并且不使用内存来存储任何数据。因此,DOM比较适合文档较小而数据访问模式复杂的情况,相反情况下,则使用SAX。

然而事实却并不这么单纯。很多情况下,开发者不情愿使用复杂的SAX,但又不得不用,因为没有其他选择。此外,即使XML文件的大小只是稍微大于几百K,DOM的内存开销和性能迟滞也会成为棘手的障碍,使得程序无法达到项目所要求的最低性能目标。

那 么是否SAX的性能真得好得多?实际上,SAX所吹嘘的解析性能――通常比DOM快几倍――常常是不现实的。事实显示,SAX笨拙的,只能往前的解析不仅 在使用时相当不便,而且当文档结构稍微复杂时,也会遇到性能问题。如果开发人员不想多次扫描文档,那么就需要对文档进行缓冲,或构建自己的对象模型。

不 管使用哪种方法,性能都会成为问题,正如Apache Axis所证明的那样。在Axis的FAQ页面,它声称使用了SAX来构建高性能的实现,但它仍然使用了他们自己的和DOM非常相像的对象模型。但与它的 前任 (Apache SOAP) 相比,这种做法并没有带来明显的性能提升。而且,SAX无法处理XPath,一般来说也无法驱动XSLT (Extensible Stylesheet Language Transformation) 的处理。因此,SAX仍然无法真正解决XML处理中的问题。

为了寻找一个更易用的SAX的取代方案,越来越多的开发人员开使转向StAX (Streaming API for XML)。与SAX相比,StAX使用从XML文件中提取标记的方法,而不是回调。这种方案显著地改善了可用性,但一个基本的问题仍然存在――StAX的 只能往前的解析对于程序员依然不便,而且存在隐藏的性能损失。

底线是:任何想得到广泛应用的XML处理模型,必需能够完整体现XML的层次结构。这是因为,XML是被设计为在WEB上传输复杂数据的,因此完整展现它的结构信息也是它的任务之一。

作者:Jimmy Zhang; rainy14f(作者的blog: http://shaofan.blogjava.net)
原文: http://www.javaworld.com/javaworld/jw-03-2006/jw-0327-simplify.html
Matrix: http://www.matrix.org.cn/resource/article/44/44529_VTD-XML.html
关键字:VTD-XML;DOM;SAX

VTD-XML改变了游戏

假设我们要从头开始一个XML处理过程,并克服上面提到的DOM和SAX的种种缺点,那么这个新的模型应该具有以下属性:

* 随机访问能力:处理模型应该允许开发人员方便访问文档的某种层次结构,比如,使用XPath,或手动。
* 高性能:性能上与DOM及SAX相比,应有显著提高,而且这个“性能”应该是真实的,就是说,应该把建立文档层次结构的时间也算上。
* 低内存占用率:要使该模型能够被广泛应用于各种场景,不管文件的大小,那它就必须能够以最低的内存消耗来表现XML的结构。

VTD -XML就是一个实现了这些目标的下一代的开源XML处理模型。它相比于DOM和SAX有着本质和全面的改进。VTD-XML的一个关键优化是非提取符号 (non-extractive tokenization)。在其内部,VTD-XML在内存中保存完整及未解码的XML消息,并使用一个二进制编码规范来唯一地表示每个符号。这种规范 被称为Virtual Token Descriptor(虚拟符号描述符)。每个VTD记录都是一个64字节的整数,它对XML中符号的长度,起始偏移量,类型,嵌套深度进行了编码。

再 简单地介绍一下VTD-XML的历史,也许你会感兴趣:最初这个概念是被用来在特定硬件设备上使用,以使这些硬件(如路由器,交换机)可以高速处理 XML,比如FPGA,ASIC。此后,VTD-XML项目组决定使它开源,并于2004年五月发布了VTD-XML的最初版本,0.5版,用JAVA实 现。从那时起。VTD-XML经历了多次改进并越来越成熟。在0.8版本中,C语言版本的VTD-XML与JAVA版同时发布。在1.0版中引入了对 XPath的内建支持,于2005年10月发布。最新的版本是1.5版,它的解析引擎被重新编写以实现更强的模块化和更高的性能。

同样, 在这个版本中还出现了一个新的特性,叫作缓冲重用。它的基本概念是,当XML应用需要通过网络连接来反复地读入XML文档时,该应用会重用在第一次处理中 分配的内存缓冲。换句话说,即一次分配,多次使用。就VTD-XML来讲,这个特性完全消除了在处理XML过程中建立对象和垃圾回收的开销(在DOM和 SAX中占用50%至80%的开销)。在该项目的网站上,提供有最新的软件下载和深层技术说明。


一个简短例子

为了使你更好地了解VTD-XML编程的风格,本文首先对用VTD-XML和DOM解析和访问一个简单的XML文件进行对比。该文件名为test.xml,内容如下:
<purchaseOrder orderDate="1999-10-21">
       <item partNum="872-AA">
         <productName>Lawnmower</productName>
         <quantity>1</quantity>
         <USPrice>148.95</USPrice>
       </item>
</purchaseOrder>


VTD-XML版本的程序如下:
import com.ximpleware.*;
import com.ximpleware.parser.*;
import java.io.*;

public class use_vtd {
    public static void main(String[] args){
        try{
            File f = new File("test.xml");
            FileInputStream fis = new FileInputStream(f);
            byte[] ba = new byte[(int)f.length()];
            fis.read(ba);
            VTDGen vg = new VTDGen();
            vg.setDoc(ba);
            vg.parse(false);
            VTDNav vn = vg.getNav();
            if (vn.matchElement("purchaseOrder")){
                System.out.println(" orderDate==>"
                    + vn.toString(vn.getAttrVal("orderDate")));
                if (vn.toElement(VTDNav.FIRST_CHILD,"item")){
                    if (vn.toElement(VTDNav.FIRST_CHILD)){
                        do {
                            System.out.print( vn.toString(vn.getCurrentIndex()));
                                System.out.print("==>");

                            System.out.println( vn.toString(vn.getText()));
                        } while(vn.toElement(VTDNav.NEXT_SIBLING));
                    }
                }
            }
        }
        catch (Exception e){
            System.out.println("exception occurred ==>"+e);
        }
    }
}


实现同样功能的DOM版本的程序:
import java.io.*;
import org.w3c.dom.*;
import org.w3c.*;
import javax.xml.parsers.*;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.*;
import org.xml.sax.SAXException;

public class use_dom {
    public static void main(String[] args){
        try{
            DocumentBuilderFactory factory =
            DocumentBuilderFactory.newInstance();
            DocumentBuilder parser = factory.newDocumentBuilder();
            Document d= parser.parse("test.xml");
            Element root = d.getDocumentElement();
            if (root.getNodeName().compareTo("purchaseOrder")==0){
                System.out.println(" orderDate==> "
                    + root.getAttribute("orderDate"));

                Node n = root.getFirstChild();
                if (n != null){
                    do {
                        if (n.getNodeType() == Node.ELEMENT_NODE
                            && n.getNodeName().compareTo("item")==0){
                            Node n2 = n.getFirstChild();
                            if (n2!=null){
                                do {
                                    if (n2.getNodeType()
                                        == Node.ELEMENT_NODE){    
                                        System.out.println(
                                            n2.getNodeName()
                                            + "==>" +
                                            n2.getFirstChild().getNodeValue()
                                        );
                                    }
                                }while((n2=n2.getNextSibling())!=null);
                            }
                        }
                    }while ((n=n.getNextSibling()) != null );
                }
            }
        }
        catch (Exception e){
            System.out.println("exception occurred ==>"+e);
        }    
    }
}


像以上所展示的那样,VTD-XML使用基于游标的API来访问XML层次结构。相比之下,DOM API通过请求对象的引用来达成同样目标。VTD-XML的项目网站提供更多详细的技术资料和示例程序。

VTD-XML的基准测试

下 面,我们来比较一下VTD-XML一些流行的XML解析器的性能和内存占用情况。值得注意的是,多数包含基准测试数据的文章,如Dennis Sosnoski于2002年4月发表在JavaWorld上的“XML Documents on the Run”,都是多年前的文章。自那以后,如摩尔定律所示,更好更快的硬件大量涌现并越来越便宜。同时,XML解析与JVM技术也并未止步不前――在一些关 键领域做出了改进。

测试设置
测试平台是Sony VAIO笔记本电脑,使用Pentium M 1.7 GHz处理器(2MB L2 cache),512MB DDR2内存。前端总线频率为400MHz。操作系统为Windows XP Professional Edition with Services pack 2。JVM版本为1.5.0_06。
对以下XML解析器的最新版本进行了基准测试:
*Xerces DOM 2.7.1, 带有及不带有延迟节点扩展(deferred node expansion)
*Xerces SAX 2.7.1
*Piccolo SAX 1.04
*XPP3 1.1.3.4.O
*VTD-XML 1.5, 带有及不带有缓冲重用

在测试中我使用了大量不同大小和不同复杂程度的XML文档。从文档大小上,我把它们分为三类:小文件(小于10KB);中文件(10KB至1MB);大文件(大于1MB)。
在 全部的性能度量中我都使用了服务器的JVM来获取最高性能。在这些测试中,基准测试程序首先会多次解析或访问文档,使JVM对字节码进行即时动态优化,之 后才取得性能的平均值作为最终结果。为了减少由于磁盘IO导致的时间差别,基准测试程序在测试运行之前已经把XML文件读入到内存中。

注意:有兴趣的读者可以从资源下载基准测试程序。

吞吐量对比解析
本节在延迟时间和吞吐量上对XML解析性能进行描述。要注意的是VTD-XML与DOM可直接进行比较,而与SAX或Pull直接对比就很不公平,因为它们不在内存中构建任何层次结构。因此SAX和Pull的性能在此只作为额外参考。
吞吐量

image
图 1. 小文件.
    
image
图 2. 中文件.
    
image
图 3. 大文件.

延迟时间对比
表 1. 小文件
image

表 2. 中文件
image
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值