﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-爪哇一角 ( 孙 琳 的 博 客 )-文章分类-xml</title><link>http://www.blogjava.net/ocean07000814/category/16570.html</link><description>共同探讨STRUTS#HIBERNATE#SPRING#EJB等技术</description><language>zh-cn</language><lastBuildDate>Fri, 02 Mar 2007 06:51:58 GMT</lastBuildDate><pubDate>Fri, 02 Mar 2007 06:51:58 GMT</pubDate><ttl>60</ttl><item><title>新兴XML处理方法VTD-XML介绍</title><link>http://www.blogjava.net/ocean07000814/articles/77160.html</link><dc:creator>非洲小白脸</dc:creator><author>非洲小白脸</author><pubDate>Wed, 25 Oct 2006 04:31:00 GMT</pubDate><guid>http://www.blogjava.net/ocean07000814/articles/77160.html</guid><wfw:comment>http://www.blogjava.net/ocean07000814/comments/77160.html</wfw:comment><comments>http://www.blogjava.net/ocean07000814/articles/77160.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/ocean07000814/comments/commentRss/77160.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/ocean07000814/services/trackbacks/77160.html</trackback:ping><description><![CDATA[
		<span class="t18"> 
<p>序言 </p><p>本文所提及的VTD-XML并非本文作者原创，作者只是对它进行介绍。 </p><p>问题 </p><p>通常当我们提起XML的使用时，最头痛的部分便是XML的verbosity与XML的解析速度，当需要处理大XML文件时这个问题便变得格外严重。我在这里提及的，便是如何优化XML处理速度的话题。 </p><p>当我们选择处理XML文件的时候，我们大致上有两种选择： </p><p>DOM，这是W3C的标准模型，它将XML的结构信息以树形的方式构建，提供了遍历这颗树的接口与方法。 <br />SAX，一种低级的parser，逐元素的向前只读处理，不含有结构信息。<br />以上两种选择都各有利弊，但是都不是特别好的解决方案，它们的优缺点如下： </p><p>DOM</p><p>优点：易用性强，因为所有的XML结构信息都存在于内存中，并且遍历简单，支持XPath。 <br />缺点：Parsing速度太慢，内存占用过高（原文件的5x~10x），对于大文件来说几乎不可能使用。<br />SAX </p><p>优点：Parsing速度快，内存占用不与XML的大小相联系（可以做到XML涨内存不涨）。 <br />缺点：易用性差，因为没有结构信息，并且无法遍历，不支持XPath。如果需要结构的话只能读一点构造一点，这样的可维护性特别的差。<br />我们可以看出，基本上DOM与SAX是正好相反的两个极端，但是任何一个都不能很好的满足我们的大部分要求，我们需要找出另外一种处理方法来。注意XML的效率问题并不是XML本身的问题，而是处理XML的Parser的问题，就像我们在上面看到的两种方法有不同的效率权衡一样。</p><p>思考 </p><p>我们很喜欢类似DOM的使用方法，因为我们可以遍历，这意味着可以支持XPath，大大增强了易用性，但是DOM的效率很低。就像我们已经知道，效率问题出在处理机制上。那么，DOM到底有哪些方面影响了它的效率呢？下面让我们来做一个全面的解剖：</p><p>在当今大多数基于虚拟机（托管，或任何类似机制）技术的平台下，对象的创建销毁是一个耗时的作业（这里值得主要是Garbage Collection的耗时），DOM机制中所运用的大量的对象创建销毁无疑是影响其效率的原因之一（会引发过多的Garbage Collection）。 <br />每个对象都会额外有32bits用来存储它的内存地址，当像DOM一样拥有大量对象的时候这个额外开支也是不小的。 <br />引起以上两个问题的最主要的效率问题在于，DOM与SAX都是extractive parsing模式，这种解析模式注定了DOM与SAX都需要大量的创建（销毁）对象，引起效率问题。所谓的extractive parsing就是说在解析XML时，DOM或SAX会提取一部分原文件（一般来说是一个字符串），然后在内存中进行解析构建（输出自然就是一个或一些对象了）。拿DOM这个例子来说，DOM会将每一个element, attribute, processing-instruction, comment等等都解析成对象并给与结构，这就是所谓的extractive parsing。 <br />由extractive的问题带来的另一个问题便是更新效率，在DOM中（SAX因为不支持更新所以根本不提它），每一次需要做改动时，我们要做的就是将对象的信息再解析回XML的字符串，注意这个解析是个完整的解析，也就是说，原文件并没有被利用，而是直接将DOM模型重新完整解析成XML字符串。换句话讲，也就是DOM并不支持Incremental Update（增量更新）。 <br />另一个很可能不被注意到的“小”问题便是XML的编码，无论是何种解析方法都需要能够处理XML的编码，也就是说，在读取的时候解码，在写入的时候编码。DOM的另一个效率问题便是当我对于一个大XML只想做很小的一块儿修改的时候它也必须首先将整个文件进行解码，然后构建结构。无形中又是一个开销。<br />让我们来总结一下问题，简单的讲DOM的效率问题主要出在它的extractive parsing模式上（SAX也是一样，有同样的问题），由此引发了一系列相关问题，如果可以击破这些效率瓶颈的话那么可以想象XML的处理效率将进一步的得到提高。如果XML的易用性与处理效率得到飞跃性的提高的话，那么XML的应用范围，应用模式将得到更一步的升华，或许由此可以产生出许许多多精彩的以前连想都没有想过的基于XML的产品来。</p><p>出路 </p><p>VTD-XML便是对以上问题的思考后给出的答案，它是一个non-extractive XML parser，由于它出色的机制，很好的解决（避免）了上面所提出的各种问题，并且还“顺便”带来了non-extractive的其他好处，像快速的解析与遍历、XPath的支持、Incremental Update等等。我这里有一组数据，取自于VTD-XML的官方网站： </p><p>VTD-XML的解析速度是SAX（with NULL content handler）的1.5x~2.0x。With NULL content handler的意思就是说SAX解析中没有插入任何额外的处理逻辑，也就是SAX的最高速度。 <br />VTD-XML的内存占用是原XML的1.3x~1.5x（其中1.0x的部分是原XML，0.3x~0.5x是VTD-XML占用的部分），而DOM的内存占用则是原XML的5x~10x。举一个例子，如果一个XML的大小是50MB，那么用VTD-XML读取进来内存占用会在65MB~75MB之间，而DOM的内存占用则会在250M~500MB之间。基于这个数据用DOM处理大的XML文件几乎是不可能的选择。<br />你可能会觉得不可思议，真的可以做出比DOM易用性还好，比SAX还快的XML解析器吗？别急着下定论，还是来看看VTD-XML的原理吧！</p><p>基本原理 </p><p>就像大多数好的产品一样，VTD-XML的原理并不复杂，而是很巧妙。为了实现non-extractive这个目的，它将原XML文件原封不动的以二进制的方式读进内存，连解码都不做，然后在这个byte数组上解析每个element的位置并把一些信息记录下来，之后的遍历操作便在这些保存下来的record上进行，如果需要提取XML内容就利用record中的位置等信息在原始byte数组上进行解码并返回字符串。这一切看起来都很简单，但是，这个简单的过程确有多个性能细节在里边，并且隐藏了若干个潜在的能力。下面我们首先来描述一下各个性能细节：</p><p>为了避免过多的对象创建，VTD-XML决定采用原始的数值类型作为record的类型，这样就可以不必用heap。VTD-XML的record机制就叫做VTD（Virtual Token Descriptor），VTD将性能瓶颈在tokenization阶段就解决掉了真的是很巧妙很用心的做法。VTD是一个64bits长度的数值类型，记录了每个element的起始位置（offset），长度（length），深度（depth）以及token的类型（type）等信息。 <br />注意VTD是固定长度的（官方决定用64bits），这样做的目的就是为了提高性能，因为长度固定，在读取，查询等操作的时候格外的高效（O(1)），也就是可以用数组这种高效的结构来组织VTD大大减少了因为大量使用对象而产生的性能问题。 <br />VTD的超能力（一点都不夸张地说）就在于它能够将XML这种树形的数据结构简单的变换成对一个byte数组的操作，任何你能想象到的对于byte数组的操作都可以应用在XML上了。这是因为读取进来的XML是二进制的（byte数组），而VTD则记录了每个element的位置等访问用信息，当我们找到要操作的VTD的时候，只要用offset与length等信息就可以对原始byte数组进行任何操作，或者可以直接对VTD进行操作。举例来说，我想在一个大XML中找出一个element并删除它，那么我只需要找到这个element的VTD（遍历方法稍候再讲），将这个VTD从VTD数组中删除，然后再利用所有的VTD写出到另一个byte数组中就可以了，因为删除的VTD标明了要删除的element的位置，所以在新写入的byte数组中就不会出现这段element了，用VTD写入新的byte数组实际上就是一个byte数组的拷贝，其效率相当的高，这就是所谓的增量更新（incremental update）。<br />关于VTD-XML的遍历方式，它采用了LC (Location Cache)，简单地说就是将VTD以其深度作为标准构建的一个树形的表结构。LC的entry也是64bits长的数值类型，前32bits代表一个VTD的索引（index），后32bits代表了这个VTD的第一个child的索引。利用这些信息就可以计算出任何一个你想要到达的位置了，关于具体的遍历方法请参看官方网站的文章。基于这种遍历方式的VTD-XML有与DOM不同的操作接口，这是可以理解的，并且，VTD-XML的这种遍历方式可以在最少的几步内将你带到你所需要的地方去，遍历的性能十分突出。</p><p>总结 </p><p>就像你上面看到的，VTD-XML有着迷人的特性，而如今的1.5版本中已经加入了XPath的支持（只要可以遍历，就可以支持XPath，这是早晚的事:-)），它的实用性已经超越了当今我们所想象的范围了。另一个VTD-XML的超能力，就是基于它现在的处理方式，完全可以支持将来的Binary XML标准，并通过Binary化将XML的应用推向更高一层楼！这也是我目前所期待的！:-)</p><p>不过，VTD-XML仍然有许多需要改进与完善的地方，这方面值得我们努力与探讨。</p><p>顺便提一下，VTD-XML是开源项目（GPL），目前有Java、C两种平台支持。如果你想在.NET试一试的话建议你使用IKVM（BSD style license）将VTD-XML转换成.NET程序集，相信你会喜欢上它的！;-) </p></span>
<img src ="http://www.blogjava.net/ocean07000814/aggbug/77160.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/ocean07000814/" target="_blank">非洲小白脸</a> 2006-10-25 12:31 <a href="http://www.blogjava.net/ocean07000814/articles/77160.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>