VTD-XML是一种无提取的XML解析方法,它较好的解决了DOM占用内存过大的缺点,并且还提供了快速的解析与遍历、对XPath的支持和增量更新等特性。VTD-XML是一个开源项目,目前有Java、C两种平台支持。
为了实现non-extractive(非提取)这个目的,它将原XML文件原封不动的以二进制的方式读进内存,连解码都不做,然后在这个二进制byte数组上解析每个 element的位置并把一些信息记录下来,这种记录就被成为VTD(Virtual Token Descriptor,虚拟令牌描述符)。
之后的遍历操作便在这些保存下来的记录上进行,如果需要提取XML内容就利用记录中的位置等 信息在原始byte数组上进行解码并返回字符串。
VTD(Virtual Token Descriptor,虚拟令牌描述符)结构:
VTD是一个64bits定长的数值类型,记录了每个元素的起始位置(offset),长度(length),深度(depth)以及令牌(元素标签)的类型(type)等信息。
如下图,表示了每个元素的位置及类型信息,对Xml的所有操作都是基于这个数据结构。
下图表示了VTD目前所支持的所有元素的类型(12种):
查询与更新:
如果需要提取XML内容,就查找VTD数组,利用VTD记录中的位置等信息在原始比特数组上进行解码并返回字符串。
而且VTD-XML还可以高效的实现增量更新,例如,如果想在一个大型XML文档中找出一个节点元素并删除它,那么只需要找到这个元素的VTD,将这个VTD从VTD数组中删除,然后再利用所有的VTD写出到另一个二进制数组中就可以了,这就是所谓增量更新。这个过程实际上就是一个二进制数组的拷贝过程,其效率是非常高的。
第三部分:应用实例
VTD-XML解析xml通常经过以下几步:
1.以一个byte数组开始(存放xml);
2.利用VTDGen进行解析;
3. 利用VTDNav进行导航定位;
4. 节点遍历使用Autopilot;
5. 利用Xpath进行节点选择
6. 增量更新使用XMLModifier
下面的代码主要功能:首先根据Xpath选择某些属性partNum='872-AA' 的item元素并用someting元素替换;替换价格小于40的元素文本为200.
/* In this java program,we demonstrate how to use XMLModifier to incrementally * update an simple XML purchase order. * a particular name space. We also are going * to use VTDGen's parseFile to simplify programming. */ import java.io.File; import java.io.FileOutputStream; import com.ximpleware.AutoPilot; import com.ximpleware.ModifyException; import com.ximpleware.NavException; import com.ximpleware.VTDGen; import com.ximpleware.VTDNav; import com.ximpleware.XMLModifier; public class update { public static void main(String argv[]){ try { // open a file and read the content into a byte array VTDGen vg = new VTDGen(); String path = update.class.getResource("").getPath(); System.out.println(path); if (vg.parseFile(path + "oldpo.xml",true)){ VTDNav vn = vg.getNav(); File fo = new File("f:/newpo.xml"); FileOutputStream fos = new FileOutputStream(fo); AutoPilot ap = new AutoPilot(vn); XMLModifier xm = new XMLModifier(vn); ap.selectXPath("/purchaSEOrder/items/item[@partNum='872-AA']"); int i = -1; while((i=ap.evalXPath())!=-1){ xm.remove(); xm.insertBeforeElement("<something/>\n"); } ap.selectXPath("/purchaSEOrder/items/item/USPrice[.<40]/text()"); while((i=ap.evalXPath())!=-1){ xm.updateToken(i,"200"); } xm.output(fos); fos.close(); } } catch (NavException e){ System.out.println(" Exception during navigation "+e); } catch (ModifyException e){ System.out.println(" Modify exception occurred "+e); } catch (Exception e){ } }
<?xml version="1.0" encoding="UTF-8"?>
<purchaSEOrder orderDate="1999-10-20">
<comment>Hurry,my lawn is going wild!</comment>
<items>
<item partNum="872-AA">
<productName>Lawnmower</productName>
<quantity><![CDATA[1]]></quantity>
<USPrice>148.95</USPrice>
<comment>Confirm this is electric</comment>
</item>
<item partNum="926-AA">
<productName>Baby Monitor</productName>
<quantity>1</quantity>
<USPrice>39.98</USPrice>
<shipDate>1999-05-21</shipDate>
</item>
</items>
</purchaSEOrder>
<?xml version="1.0"?>
<purchaSEOrder orderDate="1999-10-20">
<comment>Hurry,my lawn is going wild!</comment>
<items>
<something/>
<item partNum="926-AA">
<productName>Baby Monitor</productName>
<quantity>1</quantity>
<USPrice>200</USPrice>
<shipDate>1999-05-21</shipDate>
</item>
</items>
</purchaSEOrder>