在 Java 中解析 XML,主流常用的方法有四种:DOM、SAX、JDOM 和 DOM4J 。
其中,DOM 和 SAX 是两种不同的 XML 解析方式,JDK 已经提供了支持 DOM 方式和 SAX 方式的具体实现,因此可以不引入第三方 jar 包来使用这两种解析方式。
JAXP(Java API for XML Processing
):JAXP 类库是 JDK 的一部分,它由以下几个包及其子包组成:
org.w3c.dom
提供 DOM 方式解析 XML 的标准接口。
org.xml.sax
提供 SAX 方式解析 XML 的标准接口。
javax.xml
提供 StAX 方式解析 XML 的标准接口和解析 XML 的类。
JDOM 和 DOM4J 是在这两种方式的基础上发展出的 XML 解析类库,看名字就知道这是只能在 Java 平台使用的类库。
需要注意的是:DOM 和 SAX 是两种解析 XML 的方式,这两种方式与编程语言无关,针对不同的编程语言都有具体的实现。而在 Java 中,针对这两种方式及衍生方式实现的类库有很多,有 JDK 自带的 DOM 解析类库、SAX 解析类库和 StAX 解析类库(和 SAX 类似但有区别),还有第三方的 DOM4J 解析类库和 JDOM 解析类库等。
DOM(Document Object Model) DOM 是与平台和编程语言无关的 W3C 的标准,基于 DOM 文档树,在使用时需要加载和构建整个文档形成一棵 DOM 树放在内存当中。
优点
允许应用程序对数据和结构做出更改,即 CRUD 操作。 访问是双向的,可以在任何时候在树中上下导航,获取和操作任意部分的数据。
缺点
需要加载整个 XML 文档来构造层次结构,文档越大,消耗资源越多。
在使用 DOM 的方式解析 XML 之前,需要了解 DOM 中的节点类型:
W3C XML DOM 节点类型:http://www.w3school.com.cn/xmldom/dom_nodetype.asp
常用的节点:
节点类型
描述
NodeType
nodeName
nodeValue
Document
表示整个文档(DOM 树的根节点)
9
#document
null
Element
表示 element(元素)元素
1
element name
null
Attr
属性名称
2
属性名称
属性值
Text
表示元素或属性中的文本内容
3
#text
节点内容
Comment
表示注释
8
#comment
注释文本
DOM 解析过程及常用方法:
使用 JAXP 的 DOM 解析方式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <?xml version="1.0" encoding="UTF-8" ?> <root > <animate id ="0" > <name > 希德尼娅的骑士 </name > <published > 2014.04</published > </animate > <animate id ="1" > <name > 恶之华 </name > <published > 2013.04</published > </animate > <animate id ="2" > <name > 化物语 </name > <published > 2009.07</published > </animate > <animate id ="3" > <name > 穿越时空的少女 </name > <published > 2006.07</published > </animate > </root >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 package com.nekolr;import org.w3c.dom.*;import javax.xml.parsers.DocumentBuilder;import javax.xml.parsers.DocumentBuilderFactory;import java.util.Objects;public class DOMResolver { public static final String URI = System.getProperty("user.dir" ) + "/target/classes/nekolr.xml" ; public static void main (String[] args) throws Exception { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); Document doc = db.parse(URI); Element root = doc.getDocumentElement(); Node comment = doc.getFirstChild(); NodeList nodeList = doc.getElementsByTagName("animate" ); for (int i = 0 , len = nodeList.getLength(); i < len; i++) { Node node = nodeList.item(i); if (node.hasAttributes()) printNodeAttrs(node); if (!node.hasChildNodes()) System.out.println("nodeName=" + node.getNodeName() + ", Text=" + node.getTextContent()); getChildNodes(node); } } public static void printNodeAttrs (Node node) { NamedNodeMap attrs = node.getAttributes(); if (!Objects.isNull(attrs)) { for (int i = 0 ; i < attrs.getLength(); i++) { Node attr = attrs.item(i); String name = attr.getNodeName(); String value = attr.getNodeValue(); System.out.println("nodeName=" + node.getNodeName() + ", attr=" + name + ", value=" + value); } } } public static void getChildNodes (Node node) { NodeList childNodes = node.getChildNodes(); for (int j = 0 ; j < childNodes.getLength(); j++) { Node child = childNodes.item(j); if (child.getNodeType() == Node.ELEMENT_NODE) { if (child.hasAttributes()) printNodeAttrs(child); if (!child.hasChildNodes()) System.out.println("nodeName=" + child.getNodeName() + ", Text=" + child.getTextContent()); else getChildNodes(child); } else if (child.getNodeType() == Node.TEXT_NODE && !"" .equals(child.getNodeValue().trim())) { System.out.println("nodeName=" + node.getNodeName() + ", Text=" + child.getTextContent()); } } } }
SAX(Simple API for XML) 与 DOM 的方式不同,SAX 方式不需要构建整个文档,基于流模型中的推(PUSH)模型,由事件驱动,从文档开始顺序扫描,每发现一个节点就引发一个事件,事件推给事件处理器,通过回调方法完成解析,因此读取文档的过程就是解析文档的过程。使用 SAX 需要两部分:SAX 解析器和事件处理器,其中事件处理器需要开发者提供,一般通过继承默认的事件处理器 DefaultHandler,重写需要的方法即可。
优点
不需要等待所有数据都被处理,分析就能立即开始。 只在读取数据时检查数据,不需要保存在内存中。 可以在某个条件得到满足时停止解析,不必解析整个文档。 效率和性能较高,能解析大于系统内存的文档。
缺点
需要应用程序自己负责节点的处理逻辑(例如维护父/子关系等),文档越复杂程序就越复杂。 单向导航,无法定位文档层次,很难同时访问同一文档的不同部分数据,不支持 XPath。 只能读取文档,不能进行其他操作(新增、修改和删除)。
SAX 解析过程及使用:
使用 JAXP 的 SAX 解析方式(解析的 xml 同上):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 package com.nekolr;import org.xml.sax.Attributes;import org.xml.sax.SAXException;import org.xml.sax.helpers.DefaultHandler;public class SAXParserHandler extends DefaultHandler { boolean isName = false ; boolean isPublished = false ; @Override public void startDocument () throws SAXException { System.out.println("******文档解析开始******" ); } @Override public void endDocument () throws SAXException { System.out.println("******文档解析结束******" ); } @Override public void startElement (String uri, String localName, String qName, Attributes attributes) throws SAXException { if ("animate" .equals(qName)) { System.out.println("nodeName=" + qName + ", id=" + attributes.getValue("id" )); } else if ("name" .equals(qName)) { System.out.println("start element " + qName); isName = true ; } else if ("published" .equals(qName)) { System.out.println("start element " + qName); isPublished = true ; } } @Override public void endElement (String uri, String localName, String qName) throws SAXException { System.out.println("end element " + qName); } @Override public void characters (char [] ch, int start, int length) throws SAXException { if (isName) { System.out.println(new String (ch, start, length)); isName = false ; } else if (isPublished) { System.out.println(new String (ch, start, length)); isPublished = false ; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package com.nekolr;import javax.xml.parsers.SAXParser;import javax.xml.parsers.SAXParserFactory;public class SAXDemo { public static final String URI = System.getProperty("user.dir" ) + "/target/classes/nekolr.xml" ; public static void main (String[] args) throws Exception { SAXParserFactory factory = SAXParserFactory.newInstance(); SAXParser parser = factory.newSAXParser(); parser.parse(URI, new SAXParserHandler ()); } }
JDOM(Java-based Document Object Model) 为了减少 DOM 和 SAX 的编码量出现了 JDOM,JDOM 致力于成为 Java 特定文档模型,它遵循二八定律,底层仍然使用 DOM 和 SAX(使用 SAX 解析文档),并大量使用了 JDK 的 Collections。与 DOM 类似,JDOM 也将解析的 XML 以 DOM 树的方式放入内存中。
优点
不使用接口,使用具体实现类,简化了 DOM 的 API。 大量使用 Collections,对 Java 开发友好。
缺点
由于与 DOM 类似的生成 DOM 树结构,使得 JDOM 在处理大型 XML 文档时性能较差。 灵活性差,不支持 DOM 中某些遍历。
JDOM 的使用:
使用 JDOM 解析之前的 XML 文档,因为是第三方类库,需要引入 jar 包:
1 2 3 4 5 6 7 8 9 10 <dependencies > <dependency > <groupId > org.jdom</groupId > <artifactId > jdom2</artifactId > <version > 2.0.6</version > </dependency > </dependencies >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 package com.nekolr;import org.jdom2.Attribute;import org.jdom2.Document;import org.jdom2.Element;import org.jdom2.input.SAXBuilder;import java.io.FileInputStream;import java.io.InputStreamReader;import java.util.List;public class JDOMDemo { public static final String URI = System.getProperty("user.dir" ) + "/target/classes/nekolr.xml" ; public static void main (String[] args) throws Exception { SAXBuilder saxBuilder = new SAXBuilder (); InputStreamReader in = new InputStreamReader (new FileInputStream (URI), "utf-8" ); Document doc = saxBuilder.build(in); Element root = doc.getRootElement(); List<Element> animates = root.getChildren(); for (Element animate : animates) { Attribute id = animate.getAttribute("id" ); System.out.println("nodeName=" + animate.getName() + " ,id=" + id.getValue()); List<Element> children = animate.getChildren(); for (Element child : children) { System.out.println("nodeName=" + child.getName() + ", Text=" + child.getText()); } } } }
DOM4J(Document Object Model for Java) DOM4J 大量使用 JDK 的 Collections,同时也提供了一些高性能的替代方法。支持 DOM、SAX 和 JAXP,支持 XPath。使用接口和抽象类,牺牲了部分 API 的简易性来获得更高的灵活性,同时在解析大型文档时内存占用较低。具有性能优异、功能强大、灵活性高、易用性强等优点,被现在很多开源项目使用。
使用 DOM4J 解析之前的 XML 文档,引入第三方 jar:
1 2 3 4 5 6 7 8 9 10 <dependencies > <dependency > <groupId > dom4j</groupId > <artifactId > dom4j</artifactId > <version > 1.6.1</version > </dependency > </dependencies >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 package com.nekolr;import org.dom4j.Attribute;import org.dom4j.Document;import org.dom4j.Element;import org.dom4j.io.SAXReader;import java.util.Iterator;public class DOM4JDemo { public static final String URI = System.getProperty("user.dir" ) + "/target/classes/nekolr.xml" ; public static void main (String[] args) throws Exception { SAXReader saxReader = new SAXReader (); Document doc = saxReader.read(URI); Element root = doc.getRootElement(); for (Iterator iterator = root.elementIterator(); iterator.hasNext(); ) { Element animate = (Element) iterator.next(); Attribute id = animate.attribute("id" ); System.out.println("nodeName=" + animate.getName() + " ,id=" + id.getValue()); for (Iterator iter = animate.elementIterator(); iter.hasNext(); ) { Element ele = (Element) iter.next(); System.out.println("nodeName=" + ele.getName() + ", Text=" + ele.getText()); } } } }
参考
本文部分图片引用自:http://www.cnblogs.com/Qian123/p/5231303.html