一、初识XML
由于XML具有跨平台、可读性高等特点,目前已被广泛应用。XML在百度百科查到的解读是:可扩展标记语言 (Extensible Markup Language, XML) ,用于标记电子文件使其具有结构性的标记语言,可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言。 XML是标准通用标记语言 (SGML) 的子集,非常适合 Web 传输。XML 提供统一的方法来描述和交换独立于应用程序或供应商的结构化数据。
据我所知道的XML解析技术和工具有这些:DOM、JDOM、SAX、DOM4J。
1. DOM
Document Object Model(文档对象模型,简称DOM),是W3C组织推荐的处理可扩展置标语言的标准编程接口。Document Object Model的历史可以追溯至1990年代后期微软与Netscape的“浏览器大战”,双方为了在JavaScript与JScript一决生死,于是大规模的赋予浏览器强大的功能。微软在网页技术上加入了不少专属事物,计有VBScript、ActiveX、以及微软自家的DHTML格式等,使不少网页使用非微软平台及浏览器无法正常显示。DOM即是当时蕴酿出来的杰作。
DOM可以以一种独立于平台和语言的方式访问和修改一个文档的内容和结构。DOM 是以层次结构组织的节点或信息片断的集合。这个层次结构允许开发人员在树中寻找特定信息。分析该结构通常需要加载整个文档和构造层次结构,然后才能做任何工作。由于它是基于信息层次的,因而 DOM 被认为是基于树或基于对象的。DOM 以及广义的基于树的处理具有几个优点。 首先,由于树在内存中是持久的,因此可以修改它以便应用程序能对数据和结构作出更改。它还可以在任何时候在树中上下导航,而不是像 SAX 那样是一次性的处理。DOM 使用起来也要简单得多。但对于特别大的文档,解析和加载整个文档可能很慢且很耗资源。
2. SAX
Simple APIfor XML(循序存取XML的解析器API),SAX最初是由DavidMegginson采用Java语言开发的。SAX解析器的内存使用量一般远低于DOM解析器使用量。DOM解析器在任何处理开始之前,必须把整棵树放在内存,所以DOM解析器的内存使用量完全根据输入资料的大小。相对来说,SAX解析器的内存内容,是只基于XML档案的最大深度(XML树的最大深度)和单一XML项目上XML属性储存的最大资料。这两个总是比整颗解析树本身还小。
由此可知在处理大型文件时使用SAX的效率明显高于DOM的处理效率。
3. JDOM
Java Document Object Model(Java 文档对象模型),DOM被设计为用于完成几乎所有的XML操作任务,同时它又是跨平台以及与语言无关,这就导致DOM的API庞大而复杂。为了给JAVA程序员提供一套简单易用的操作,JDOM就是为了避开DOM的缺点而产生。JDOM利用Java语言的优秀特性,包括方法重载、集合、反射以及JAVA程序员熟悉的编程风格,极大的简化了对XML文档的处理。
4. DOM4J
Document Object Model For Java,Dom4j是一个易用的、开源的库,用于XML,XPath和XSLT。它应用于Java平台,采用了Java集合框架并完全支持DOM,SAX和JAXP。
虽然 DOM4J 代表了完全独立的开发结果,但最初,它是 JDOM 的一种智能分支。它合并了许多超出基本 XML 文档表示的功能,包括集成的 XPath 支持、XML Schema 支持以及用于大文档或流化文档的基于事件的处理。它还提供了构建文档表示的选项,它通过 DOM4J API 和标准 DOM 接口具有并行访问功能。从 2000 下半年开始,它就一直处于开发之中。 为支持所有这些功能,DOM4J 使用接口和抽象基本类方法。DOM4J 大量使用了 API 中的 Collections 类,但是在许多情况下,它还提供一些替代方法以允许更好的性能或更直接的编码方法。直接好处是,虽然 DOM4J 付出了更复杂的 API 的代价,但是它提供了比 JDOM 大得多的灵活性。 在添加灵活性、XPath 集成和对大文档处理的目标时,DOM4J 的目标与 JDOM 是一样的:针对 Java 开发者的易用性和直观操作。它还致力于成为比 JDOM 更完整的解决方案,实现在本质上处理所有 Java/XML 问题的目标。在完成该目标时,它比 JDOM 更少强调防止不正确的应用程序行为。 DOM4J 是一个非常非常优秀的Java XML API,具有性能优异、功能强大和极端易用使用的特点,同时它也是一个开放源代码的软件。如今你可以看到越来越多的 Java 软件都在使用 DOM4J 来读写 XML,特别值得一提的是连 Sun 的 JAXM 也在用 DOM4J。
二 、性能测试
第一轮比较: Xml文件大小:10.7MB dom解析效率测试,执行1次,java.lang.OutOfMemoryError: Java heap space sax解析效率测试,执行1次,平均每次解析时间为:6938毫秒 jdom解析效率测试,执行1次,ava.lang.OutOfMemoryError: Java heap space dom4j解析效率测试,执行1次,java.lang.OutOfMemoryError: Java heap space 可见文件超过10Mb时除了sax外其他三种解析技术都内存溢出了,第一轮sax胜出。
第二轮比较: 为了排除JVM内存过小导致的内存溢出,这次把JVM内存调大:-Xms512m -Xmx1024m;xml文件大小不变 dom解析效率测试,执行1次,半个小时还没运行结束,myEclipse卡死 sax解析效率测试,执行1次,平均每次解析时间为:6735毫秒 jdom解析效率测试,执行1次,平均每次解析时间为:502484毫秒 dom4j解析效率测试,执行1次,平均每次解析时间为:5860毫秒 可见加大JVM内存后执行效率最高的是dom4j,其次是sax,jdom达到将近9分钟是忍无可忍的,而dom就更不用说了。第二轮比较dom4j胜出。
第三轮比较 Xml文件大小为12kb。 dom解析效率测试,执行10次,平均每次解析时间为:29毫秒 jdom解析效率测试,执行10次,平均每次解析时间为:12毫秒 sax解析效率测试,执行10次,平均每次解析时间为:9毫秒 dom4j解析效率测试,执行10次,平均每次解析时间为:11毫秒 可见在文件较小时后面三种解析技术没有很大差别,但dom的效率还是很明显。
三、综述
经过两轮的比较测试,可看出在解析大文件时dom4j效率最高,其次是sax,JDOM 和 DOM 在性能测试时表现极为不佳。在小文档情况下还值得考虑使用 DOM 和 JDOM。另外,DOM 仍是一个非常好的选择。DOM 实现广泛应用于多种编程语言。它还是许多其它与 XML 相关的标准的基础,因为它正式获得 W3C 推荐(与基于非标准的 Java 模型相对),所以在某些类型的项目中可能也需要它(如在 javascript 中使用 DOM)。 SAX表现较好,这要依赖于它特定的解析方式。一个 SAX 检测即将到来的XML流,但并没有载入到内存(当然当XML流被读入时,会有部分文档暂时隐藏在内存中)。 无疑,DOM4J是最好的,目前许多开源项目中大量采用 DOM4J,例如大名鼎鼎的 Hibernate 也用 DOM4J 来读取 XML 配置文件。如果不考虑可移植性,DOM4j是不错的选择!
四 、代码参考
<?xml version="1.0" encoding="UTF-8"?> <elements> <element> <dabh>dabh_1</dabh> <xm>黄蓉</xm> <xb>女</xb> </element> <element> <dabh>dabh_2</dabh> <xm>郭靖</xm> <xb>男</xb> </element> <element> <dabh>dabh_3</dabh> <xm>宋大牛</xm> <xb>男</xb> </element> <element> <dabh>dabh_4</dabh> <xm>宋大牛</xm> <xb>男</xb> </element> <element> <dabh>dabh_5</dabh> <xm>宋大牛</xm> <xb>男</xb> </element> <element> <dabh>dabh_6</dabh> <xm>宋大牛</xm> <xb>男</xb> </element> <element> <dabh>dabh_7</dabh> <xm>宋大牛</xm> <xb>男</xb> </element> <element> <dabh>dabh_8</dabh> <xm>宋大牛</xm> <xb>男</xb> </element> <element> <dabh>dabh_8</dabh> <xm>宋大牛</xm> <xb>男</xb> </element> <element> <dabh>dabh_9</dabh> <xm>宋大牛</xm> <xb>男</xb> </element> <element> <dabh>dabh_10</dabh> <xm>宋大牛</xm> <xb>男</xb> </element> <element> <dabh>dabh_11</dabh> <xm>宋大牛</xm> <xb>男</xb> </element> <element> <dabh>dabh_12</dabh> <xm>宋大牛</xm> <xb>男</xb> </element> <element> <dabh>dabh_13</dabh> <xm>宋大牛</xm> <xb>男</xb> </element> <element> <dabh>dabh_14</dabh> <xm>宋大牛</xm> <xb>男</xb> </element> <element> <dabh>dabh_15</dabh> <xm>宋大牛</xm> <xb>男</xb> </element> <element> <dabh>dabh_16</dabh> <xm>宋大牛</xm> <xb>男</xb> </element> <element> <dabh>dabh_17</dabh> <xm>宋大牛</xm> <xb>男</xb> </element> <element> <dabh>dabh_18</dabh> <xm>宋大牛</xm> <xb>男</xb> </element> <element> <dabh>dabh_19</dabh> <xm>宋大牛</xm> <xb>男</xb> </element> <element> <dabh>dabh_20</dabh> <xm>宋大牛</xm> <xb>男</xb> </element> <element> <dabh>dabh_21</dabh> <xm>宋大牛</xm> <xb>男</xb> </element> <element> <dabh>dabh_22</dabh> <xm>宋大牛</xm> <xb>男</xb> </element> <element> <dabh>dabh_23</dabh> <xm>宋大牛</xm> <xb>男</xb> </element> <element> <dabh>dabh_24</dabh> <xm>宋大牛</xm> <xb>男</xb> </element> <element> <dabh>dabh_25</dabh> <xm>宋大牛</xm> <xb>男</xb> </element> <element> <dabh>dabh_26</dabh> <xm>宋大牛</xm> <xb>男</xb> </element> <element> <dabh>dabh_27</dabh> <xm>宋大牛</xm> <xb>男</xb> </element> <element> <dabh>dabh_28</dabh> <xm>宋大牛</xm> <xb>男</xb> </element> <element> <dabh>dabh_29</dabh> <xm>宋大牛</xm> <xb>男</xb> </element> <element> <dabh>dabh_30</dabh> <xm>宋大牛</xm> <xb>男</xb> </element> <element> <dabh>dabh_31</dabh> <xm>宋大牛</xm> <xb>男</xb> </element> <element> <dabh>dabh_32</dabh> <xm>宋大牛</xm> <xb>男</xb> </element> </elements>
package com.xml.dom; import java.io.File; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document; import org.w3c.dom.NodeList; /** * xml解析技术之DOM * DOM 是用与平台和语言无关的方式表示 XML 文档的官方 W3C 标准。 * 对于特别大的文档,解析和加载整个文档可能很慢且很耗资源。 * 优点是编程容易。 * @fileName MyXMLReader.java * @date 2013-7-25 * @time 下午03:53:39 * @author wst * */ public class MyXMLReader { public static long test() { long startTime = System.currentTimeMillis(); try { File f = new File("src\\demo.xml"); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document doc = builder.parse(f); NodeList nl = doc.getElementsByTagName("element"); int nodeLength = (int)nl.getLength(); if(nodeLength>0){ for (int i = 0; i < nodeLength; i++) { System.out.println("-------------------------------------"); System.out.println("档案编号:"+ doc.getElementsByTagName("dabh").item(i). getFirstChild().getNodeValue()); System.out.println(" 姓名:"+ doc.getElementsByTagName("xm").item(i). getFirstChild().getNodeValue()); System.out.println(" 性别:"+ doc.getElementsByTagName("xb").item(i). getFirstChild().getNodeValue()); } } } catch (Exception e) { e.printStackTrace(); } return (System.currentTimeMillis() - startTime); } }
package com.xml.jdom; import java.io.*; import java.util.*; import org.jdom.*; import org.jdom.input.*; /** * xml解析技术之JDOM *JDOM 与 DOM 主要有两方面不同。 *首先,JDOM 仅使用具体类而不使用接口。 *这在某些方面简化了 API,但是也限制了灵活性。 *第二,API 大量使用了 Collections 类, *简化了那些已经熟悉这些类的 Java 开发者的使用。 * @fileName MyXMLReader.java * @date 2013-7-25 * @time 下午03:53:39 * @author wst * */ public class MyXMLReader { @SuppressWarnings("unchecked") public static long test() { long startTime = System.currentTimeMillis(); try { SAXBuilder builder = new SAXBuilder(); Document doc = (Document) builder.build(new File("src//demo.xml")); Element foo = (Element) doc.getRootElement(); List elementList=foo.getChildren(); for(int i=0;i<elementList.size();i++) { System.out.println("----------------------------------------"); System.out.println("档案编号:"+ ((Element)elementList.get(i)).getChild("dabh").getText()); System.out.println(" 姓名:"+ ((Element)elementList.get(i)).getChild("xm").getText()); System.out.println(" 性别:"+ ((Element)elementList.get(i)).getChild("xb").getText()); } } catch (Exception e) { e.printStackTrace(); } System.out.println("运行时间:" + (System.currentTimeMillis() - startTime) + " 毫秒"); return (System.currentTimeMillis() - startTime); } }
package com.xml.sax; import java.util.Stack; import org.xml.sax.*; import org.xml.sax.helpers.*; import javax.xml.parsers.*; /** * xml解析技术之sax * 对于特别大的文档,效率较DOM高。 * @fileName MyXMLReader.java * @date 2013-7-25 * @time 下午03:53:39 * @author wst * */ public class MyXMLReader extends DefaultHandler { @SuppressWarnings("unchecked") Stack tags = new Stack(); public MyXMLReader() { super(); } public static long test() { long startTime = System.currentTimeMillis(); try { SAXParserFactory sf = SAXParserFactory.newInstance(); SAXParser sp = sf.newSAXParser(); MyXMLReader reader = new MyXMLReader(); sp.parse(new InputSource("src\\demo.xml"), reader); } catch (Exception e) { e.printStackTrace(); } System.out.println("运行时间:" + (System.currentTimeMillis() - startTime)+ " 毫秒"); return (System.currentTimeMillis() - startTime); } public void characters(char ch[], int start, int length) throws SAXException { String tag = (String) tags.peek(); if (tag.equals("dabh")) { System.out.println("档案编号:" + new String(ch, start, length)); } if (tag.equals("xm")) { System.out.println(" 姓名:" + new String(ch, start, length)); } if (tag.equals("xb")) { System.out.println(" 性别:" + new String(ch, start, length)); } } @SuppressWarnings("unchecked") public void startElement(String uri, String localName, String qName,Attributes attrs) { tags.push(qName); } }
package com.xml.dom4j; import java.io.*; import java.util.*; import org.dom4j.*; import org.dom4j.io.*; /** * xml解析技术之dom4j * Dom4j是一个易用的、开源的库,用于XML,XPath和XSLT。 * 它应用于Java平台,采用了Java集合框架并完全支持DOM,SAX和JAXP * @fileName MyXMLReader.java * @date 2013-7-25 * @time 下午04:29:59 * @author wst * */ public class MyXMLReader { @SuppressWarnings("unchecked") public static long test() { long startTime = System.currentTimeMillis(); try { SAXReader reader = new SAXReader(); Document doc = reader.read(new File("src//demo.xml")); Element root = doc.getRootElement(); List <Element> list = root.elements("element"); Iterator <Element> it = list.iterator(); while(it.hasNext()){ System.out.println("----------------------------------------"); Element st = it.next(); System.out.println(st.getName()); System.out.println(st.elementText("dabh")); System.out.println(st.elementText("xm")); System.out.println(st.elementText("xb")); } } catch (Exception e) { e.printStackTrace(); } System.out.println("运行时间:" + (System.currentTimeMillis() - startTime)+ " 毫秒"); return (System.currentTimeMillis() - startTime); } }
五、参考资料
dom4j.chm帮助文档,百度百科等。