DOM方式:
优点:
(1) 能随意操作文档的任意一个位置不依赖于平台
(2) 其他部分平台也能够使用
(3) 双向操作,解析的同时支持修改
(4) 树形层级结构,和文档一一对应,编写代码简单
缺点:
(1) 解析前要将整个文档加载到内存构建关系层次,比较耗资源
(2)由于是加载整个文件,所以耗时较多
SAX方式:
优点:
(1)基于事件驱动模型,事件丰富
(2)逐条解析,耗费资源少
(3)速度快
缺点:
(1)在Handler中处理事件,事件丰富的同时给存储实体带来了不便
(2)单向解析,无法获取文档内任意位置,即便只是需要文档内的一个属性,也需要从头开始解析
JDOM方式:
优点:
(1)优化了DOM API
(2)纯JAVA实现, 方便JAVA开发人员使用
缺点:
(1)性能较差
DOM4j方式:
优点:
(1)支持XPath,可直接定位选取节点或节点集
(2)各方面表现优秀
(3)合并了许多超出基本XML文档表示的功能。
下面简单地写一个例子对比一下四种解析方式的速度(只是简单进行测试,仅供参考。示例代码中均屏蔽了输出):
DOM.java:
package org.devsong.xmlload;
import java.io.File;
import java.io.IOException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
public class DOM {
/**
* 获取DocumentBuilder对象
*/
public DocumentBuilder getDocumentBuilder() {
// 通过DocumentBuilderFactory的静态方法获取实例
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = null;
try {
builder = factory.newDocumentBuilder();
} catch (ParserConfigurationException e) {
e.printStackTrace();
}
return builder;
}
/**
* 开始解析
*/
public void startParse(String uri) {
try {
Document document = getDocumentBuilder().parse(new File(uri));
Element root = document.getDocumentElement(); // 根节点
// 调用parseNode方法开始递归解析
parseNode(root);
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 递归解析每一个节点
*/
public void parseNode(Node root) {
if (root == null)
return;
String nodeName = root.getNodeName();
// 输出节点名
//System.out.print(nodeName + ":");
// 获取当前节点的所有属性
NamedNodeMap nodeMap = root.getAttributes();
if (nodeMap != null) {
for (int i = 0; i < nodeMap.getLength(); i++) {
Node node = nodeMap.item(i);
// 输出属性信息
//System.out.print("[attr]" + node.getNodeName() + ":" + node.getNodeValue() + " ");
}
}
// 剔除冗余内容:空格和换行
// 在避免空指针异常的情况下如果当前获得的节点文本经过trim()之后不为空,则输出当前节点内容
if (root.getFirstChild() != null && root.getFirstChild().getNodeValue() != null
&& !(root.getFirstChild().getNodeValue()).trim().equals("")) {
String nodeValue = root.getFirstChild().getNodeValue();
//System.out.print(nodeValue + " ");
}
// 获取当前节点的所有子节点
NodeList nodeList = root.getChildNodes();
if (nodeList != null) {
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
// 剔除冗余节点(空文本段)
if (node.getNodeType() != Node.TEXT_NODE) {
// 进行递归解析每一个节点
parseNode(node);
}
}
}
}
}
JDOM.java:
package org.devsong.xmlload;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.List;
import org.jdom2.Attribute;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;
public class JDOM {
/**
* 获取Document对象
*
* @param uri
* @return
*/
private Document getDocment(String uri) {
// 获取SAXBuilder
SAXBuilder builder = new SAXBuilder();
File file = new File(uri);
Document doc = null;
try {
doc = builder.build(new FileInputStream(file));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (JDOMException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return doc;
}
/**
* 开始解析
*/
public void startParse(String uri) {
// 获取根节点,从根结点开始解析
Element ele = getDocment(uri).getRootElement();
parseNode(ele);
}
/**
* 节点递归解析
*
* @param node
*/
private void parseNode(Element node) {
//System.out.print(node.getName() + ":");
// 获取节点属性列表
List attrList = node.getAttributes();
if (attrList != null) {
// 解析所有属性
for (int i = 0; i < attrList.size(); i++) {
Attribute attr = attrList.get(i);
//System.out.print("[attr]" + attr.getName() + ":" + attr.getValue() + " ");
}
}
// 剔除空白文本
// 输出节点内容
if (node.getText() != null && !node.getText().trim().equals("")) {
//System.out.print(node.getText() + " ");
}
// 得到子节点列表,进行递归解析
List childList = node.getChildren();
if (childList != null) {
for (int i = 0; i < childList.size(); i++) {
Element child = childList.get(i);
parseNode(child);
}
}
}
}
SAX.java:
package org.devsong.xmlload;
import java.io.IOException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.devsong.myhandler.MyHandler;
import org.xml.sax.SAXException;
public class SAX {
public void startParse(String uri) {
try {
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
MyHandler handler = new MyHandler();
parser.parse(uri, handler);
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
SAX需要的 MyHandler.java:
package org.devsong.myhandler;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class MyHandler extends DefaultHandler {
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
super.startElement(uri, localName, qName, attributes);
//System.out.print(qName + ":");
if (attributes != null) {
for (int i = 0; i < attributes.getLength(); i++) {
//System.out.print("[attr]" + attributes.getQName(i) + ":" + attributes.getValue(i) + " ");
}
}
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
super.characters(ch, start, length);
String ContentTemp = new String(ch, start, length);
if (!"".equals(ContentTemp.trim())) {
//System.out.print(ContentTemp + " ");
}
}
}
Dom4j: Dom4j.java
package org.devsong.xmlload;
import java.io.File;
import java.util.List;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
public class Dom4j {
public void startParse(String uri) {
//获取SAXReader对象
SAXReader reader = new SAXReader();
try {
//利用Reader获取Document对象
Document doc = reader.read(new File(uri));
//获取根节点并进行递归解析
parseNode(doc.getRootElement());
} catch (DocumentException e) {
e.printStackTrace();
}
}
/**
* 递归解析节点
* @param node
*/
private void parseNode(Element node) {
//System.out.print(node.getName() + ":");
//获取当前节点属性列表
List attrlist = node.attributes();
if (attrlist != null) {
for (int i = 0; i < attrlist.size(); i++) {
Attribute attr = attrlist.get(i);
//System.out.print("[attr]" + attr.getName() + ":" + attr.getValue() + " ");
}
}
//剔除空白文本
//输出节点内容
if(node.getText() != null && !node.getText().trim().equals("")) {
//System.out.print(node.getText() + " ");
}
//获取所有的子节点进行递归操作
List eleList = node.elements();
if (eleList != null) {
for (Element e : eleList) {
parseNode(e);
}
}
}
}
测试代码,简单统计了一下时间: Test.java
package org.devsong.test;
import org.devsong.xmlload.DOM;
import org.devsong.xmlload.Dom4j;
import org.devsong.xmlload.JDOM;
import org.devsong.xmlload.SAX;
public class Test {
public static void main(String[] args) {
DOM dom = new DOM();
Dom4j d4j = new Dom4j();
JDOM jdom = new JDOM();
SAX sax = new SAX();
String uri = "src/res/language.xml";
long start = System.currentTimeMillis();
dom.startParse(uri);
long end = System.currentTimeMillis();
System.out.println("DOM: " + (end-start));
start = System.currentTimeMillis();
sax.startParse(uri);
end = System.currentTimeMillis();
System.out.println("SAX: " + (end-start));
start = System.currentTimeMillis();
jdom.startParse(uri);
end = System.currentTimeMillis();
System.out.println("JDOM: " + (end-start));
start = System.currentTimeMillis();
d4j.startParse(uri);
end = System.currentTimeMillis();
System.out.println("DOM4j: " + (end-start));
}
}
几次测试结果都类似,DOM用时平均下来最长。JDOM和DOM差不多,比DOM好一点点。DOM4j用时比前两者少,速度还行。SAX速度最快,用时大概为DOM的1/4左右。测试的文档为130kb大小的XML。当然,测试次数较少,测试方法可能不严谨,只是简单测试,对比结果仅供参考。