Java解析xml——DOM、SAX、JDOM和DOM4J四种方式的汇总与比较

本文对比了Java中四种XML解析方式:DOM、SAX、JDOM和DOM4J。DOM解析将XML文件全部加载到内存,适合小文件但可能导致内存溢出;SAX基于事件驱动,内存消耗小但编码繁琐;JDOM提供更便捷的API,而DOM4J功能强大且性能优异。在小文件中,SAX速度最快,大文件时DOM4J优于JDOM。

一、四种方式的对比

【DOM】

DOM解析是将xml整个读入内存中,并在内存中以DOM树的形式存储。它是与平台无关的官方解析方式,所以不止在Java平台可以用DOM解析,在其他的平台也可以使用。

-优点:

1、树形结构,直观,易于理解,读取方便,代码易编写。

2、树形结构保存在内存中,容易修改。

-缺点

1、因为DOM是将xml文件整个读入内存中,所以对内存消耗大,在xml文件较大时,很容易造成内存溢出的情况。

【SAX】

SAX解析是Java独有的xml文件解析方式,是基于事件驱动的,每当Java程序读到xml文件中的标签头或读到标签结尾时,会触发相应的事件进行业务的处理。

-优点:

1、基于事件驱动,对内存消耗小。

2、适用于只需要处理xml文件中的数据的情况。

-缺点:

1、因为是基于事件驱动的,所以需要针对每一种事件都要编写相应的处理方法,编码比较繁琐。

2、因为SAX并不是一次性把xml读入内存中而是依次读入xml的数据的,所以不能同时操作同一个xml文件中的多个不同的数据。

【JDOM】

DOM和SAX是Java提供的两种基础的解析xml的方式,而JDOM是在基础方法上的扩展,要使用JDOM解析xml文件,需要额外导入jar包。

-优点

1、仅使用具体类而不是用接口。

2、JDOM的API大量使用了Collections类,操作更加方便。

【DOM4J】

DOM4J和JDOM一样,是在Java提供的基础解析xml方式上的扩展,要使用DOM4J也需要导入额外的jar包。

-优点

1、功能强大,能够处理更加复杂的xml文档,包含一些超出基本xml文档的功能。

2、性能优异,对处理较大的xml文件尤为明显。


二、四种方式解析xml文件的性能测试

XmlUtil.java

/**
 * 这个类中包含了四种解析XML方式的具体方法
 * @author Dan
 *
 */
public class XmlUtil {
	
	/**
	 * DOM解析方式
	 */
	public void domParseXml() {
		System.out.println("=========DOM解析==========");
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		try {
			DocumentBuilder builder = factory.newDocumentBuilder();
			Document document = builder.parse("xml/books.xml");
			
			NodeList nodeList = document.getElementsByTagName("book");
			for(int i = 0; i < nodeList.getLength(); i++) {
				System.out.println("======开始读取书本信息======");
				Node node = nodeList.item(i);
				
				NamedNodeMap attrs = node.getAttributes();
				for(int j = 0; j < attrs.getLength(); j++) {
					Node attr = attrs.item(j);
					System.out.println("属性名:" + attr.getNodeName() + "-->属性值:" + attr.getNodeValue());
				}
				
				NodeList childList = node.getChildNodes();
				for(int k = 0; k < childList.getLength(); k++) {
					Node child = childList.item(k);
					if(Node.ELEMENT_NODE == child.getNodeType()) {
						System.out.println("子节点名:" + child.getNodeName() + "-->子节点值:" + child.getTextContent());
					}
				}
				System.out.println("======读取书本信息结束======");
			}
			
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}	
	}
	
	/**
	 * SAX解析方式
	 */
	public void saxParseXml() {
		SAXParserFactory factory = SAXParserFactory.newInstance();
		try {
			SAXParser parser = factory.newSAXParser();
			SAXHandler handler = new SAXHandler();
			parser.parse("xml/books.xml", handler);
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * JDOM解析方式
	 */
	public void jdomParseXml() {
		System.out.println("==========JDOM解析==========");
		SAXBuilder builder = new SAXBuilder();
		try {
			org.jdom2.Document document = builder.build(new File("xml/books.xml"));
			
			Element root = document.getRootElement();
			List<Element> childList = root.getChildren();
			for (Element child : childList) {
				System.out.println("======开始读取书本信息======");
				List<Attribute> attrs = child.getAttributes();
				for(Attribute attr : attrs) {
					System.out.println("属性名:" + attr.getName() + "-->属性值:" + attr.getValue());
				}
				
				List<Element> eleList = child.getChildren();
				for(Element element: eleList) {
					System.out.println("子节点名:" + element.getName() + "-->子节点值:" + element.getValue());
				}
				System.out.println("======读取书本信息结束======");
			}	
		} catch (JDOMException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * DOM4J解析方式
	 */
	@SuppressWarnings("unchecked")
	public void dom4JParseXml() {
		System.out.println("==========DOM4J解析==========");
		SAXReader reader = new SAXReader();
		try {
			org.dom4j.Document document= reader.read(new File("xml/books.xml"));
			
			org.dom4j.Element root = document.getRootElement();
			List<org.dom4j.Element> childList = root.elements();
			for(org.dom4j.Element child : childList) {
				System.out.println("======开始读取书本信息======");
				List<org.dom4j.Attribute> attrs = child.attributes();
				for(org.dom4j.Attribute attr : attrs) {
					System.out.println("属性名:" + attr.getName() + "-->属性值:" + attr.getValue());
				}
				
				List<org.dom4j.Element> eleList = child.elements();
				for(org.dom4j.Element element : eleList) {
					System.out.println("子节点名:" + element.getName() + "--->子节点值:" + element.getStringValue());
				}
				System.out.println("======读取书本信息结束======");
			}
		} catch (DocumentException e) {
			e.printStackTrace();
		}
	}
}
SAXHandler.java
public class SAXHandler extends DefaultHandler {

	@Override
	public void startDocument() throws SAXException {
		super.startDocument();
		System.out.println("==========SAX解析==========");
	}

	@Override
	public void startElement(String uri, String localName, String qName,
			Attributes attributes) throws SAXException {
		super.startElement(uri, localName, qName, attributes);
		
		if("book".equals(qName)) {
			System.out.println("======开始读取书本信息======");
			for(int i = 0; i < attributes.getLength(); i++) {
				System.out.println("属性名:" + attributes.getQName(i) + "属性值" + attributes.getValue(i));
			}
		} else if(!"book".equals(qName) && !"bookstore".equals(qName)) {
			System.out.print("子节点" + qName);
		}
	}
	
	@Override
	public void characters(char[] ac, int start, int length) throws SAXException {
		super.characters(ac, start, length);
		String value = new String(ac, start, length);
		if(!"".equals(value.trim())) {
			System.out.println("--->节点值:" + value);
		}
	}
	
	@Override
	public void endElement(String uri, String localName, String qName) throws SAXException {
		super.endElement(uri, localName, qName);
		if("book".equals(qName)) {
			System.out.println("======读取书本信息结束======");
		}
	}
}

TestMain.java

public class TestMain {
	public static void main(String[] args) {
		XmlUtil util = new XmlUtil();
		long domTime, saxTime, jdomTime, dom4JTime, end;
		
		long start = System.currentTimeMillis();
		util.domParseXml();
		end = System.currentTimeMillis();
		domTime = end - start;
		
		start = System.currentTimeMillis();
		util.saxParseXml();
		end = System.currentTimeMillis();
		saxTime = end - start;
		
		start = System.currentTimeMillis();
		util.jdomParseXml();
		end = System.currentTimeMillis();
		jdomTime = end - start;
		
		start = System.currentTimeMillis();
		util.dom4JParseXml();
		end = System.currentTimeMillis();
		dom4JTime = end - start;
		
		System.out.println("DOM:" + domTime);
		System.out.println("SAX:" + saxTime);
		System.out.println("JDOM:" + jdomTime);
		System.out.println("DOM4J:" + dom4JTime);
	}
}

在xml文件较小时,例如有下面的xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
	<book id="1">
		<name>冰与火之歌</name>
		<author>乔治马丁</author>
		<time>2014</time>
		<price>89</price>
	</book>
	<book id="2">
		<name>安徒生童话</name>
		<price>40</price>
		<time>2004</time>
		<language>English</language>
	</book>
</bookstore>
运行结果(省略了输出节点信息内容,直接显示时间信息,结果可能每次都可能不同,仅作参考!):

...一系列输出
DOM:63
SAX:16
JDOM:93
DOM4J:94

可以看到JDOM和DOM4J在文件比较小的时候优势并不明显,SAX解析反而是最快的。


现在使用一个51.5KB的xml文件做实验,运行结果如下(省略了输出节点信息内容,直接显示时间信息,结果可能每次都可能不同,仅作参考!):

...一系列输出

DOM:313
SAX:156
JDOM:187
DOM4J:141

可以看到,在文件较大的情况下,DOM4J的性能优异的特点就显现出来了,而DOM是最慢的。实际的开发过程中,可以根据实际需要选择合适的方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值