XML解析方式分为两种:DOM方式和SAX方式
DOM:Document Object Model,文档对象模型。这种方式是W3C推荐的处理XML的一种方式。
SAX:Simple API for XML。这种方式不是官方标准,属于开源社区XML-DEV,几乎所有的XML解析器都支持它。
XML解析开发包
JAXP:是SUN公司推出的解析标准实现。
Dom4J:是开源组织推出的解析开发包。
JDom:是开源组织推出的解析开发包。
PullParser
JAXP:(Java API for XML Processing)开发包是JavaSE的一部分,它由以下几个包及其子包组成:
org.w3c.dom:提供DOM方式解析XML的标准接口
org.xml.sax:提供SAX方式解析XML的标准接口
javax.xml:提供了解析XML文档的类
javax.xml.parsers包中,定义了几个工厂类(DocumentBuilderFactory 、SAXParserFactory)。我们可以通过调用这些工厂类,得到对XML文档进行解析的DOM和SAX解析器对象。
使用JAXP进行DOM解析
javax.xml.parsers 包中的DocumentBuilderFactory用于创建DOM模式的解析器对象 , DocumentBuilderFactory是一个抽象工厂类,它不能直接实例化,但该类提供了一个newInstance方法 ,这个方法会根据本地平台默认安装的解析器,自动创建一个工厂的对象并返回。
1) 调用 DocumentBuilderFactory.newInstance() 方法得到创建 DOM 解析器的工厂。
2) 调用工厂对象的 newDocumentBuilder方法得到 DOM 解析器对象。
3) 调用 DOM 解析器对象的 parse() 方法解析 XML 文档,得到代表整个文档的 Document 对象,进而可以利用DOM特性对整个XML文档进行操作了
DOM模型(document object model)
a) DOM解析器在解析XML文档时,会把文档中的所有元素,按照其出现的层次关系,解析成一个个Node对象(节点)。
b) 在dom中,节点之间关系如下:
1) 位于一个节点之上的节点是该节点的父节点(parent)
2) 一个节点之下的节点是该节点的子节点(children)
3) 同一层次,具有相同父节点的节点是兄弟节点(sibling)
4) 一个节点的下一个层次的节点集合是节点后代(descendant)
5) 父、祖父节点及所有位于节点上面的,都是节点的祖先(ancestor)
c) 节点类型
Node对象提供了一系列常量来代表结点的类型,当开发人员获得某个Node类型后,就可以把Node节点转换成相应的节点对象(Node的子类对象),以便于调用其特有的方法。(查看API文档)
Node对象提供了相应的方法去获得它的父结点或子结点。编程人员通过这些方法就可以读取整个XML文档的内容、或添加、修改、删除XML文档的内容了。
更新XML文档
javax.xml.transform包中的Transformer类用于把代表XML文件的Document对象转换为某种格式后进行输出,例如把xml文件应用样式表后转成一个html文档。利用这个对象,当然也可以把Document对象又重新写入到一个XML文件中。
Transformer类通过transform方法完成转换操作,该方法接收一个源和一个目的地。我们可以通过:
1) javax.xml.transform.dom.DOMSource类来关联要转换的document对象,
2) 用javax.xml.transform.stream.StreamResult 对象来表示数据的目的地。
Transformer对象通过TransformerFactory获得。
DOM解析代码实例
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import com.itheima.domain.Book;
public class DOMUtil {
public static List<Book> getBooks(String uri) throws Exception {
List<Book> books = new ArrayList<Book>();
// 1. 通过DocumentBuilderFactory 创建一个工厂类
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
// 2. 通过工厂的newDocumnentBuilder方法获取一个DocumentBuilder
DocumentBuilder builder = factory.newDocumentBuilder();
// 3. 调用parse方法获取Document对象
Document document = builder.parse(uri);
NodeList bookNodes = document.getElementsByTagName("书");
Book book = null;
for (int i = 0; i < bookNodes.getLength(); i++) {
Element bookEle = (Element) bookNodes.item(i);
book = new Book();
String id = bookEle.getAttribute("id");
book.setId(id);
String publisher = bookEle.getAttribute("出版社");
book.setPublisher(publisher);
String bookName = bookEle.getElementsByTagName("书名").item(0)
.getTextContent();
book.setBookName(bookName);
String author = bookEle.getElementsByTagName("作者").item(0)
.getTextContent();
book.setAuthor(author);
String price = bookEle.getElementsByTagName("售价").item(0)
.getTextContent();
book.setPrice(price);
books.add(book);
book = null;
}
return books;
}
public static void addBook(Book book, String uri) throws Exception {
Document document = DocumentBuilderFactory.newInstance()
.newDocumentBuilder().parse(uri);
Node bookshelfNode = document.getElementsByTagName("书架").item(0);
Element bookEle = document.createElement("书");
bookEle.setAttribute("id", book.getId());
bookEle.setAttribute("出版社", book.getPublisher());
bookshelfNode.appendChild(bookEle);
Node bookNameNode = bookEle.appendChild(document.createElement("书名"));
bookNameNode.setTextContent(book.getBookName());
Node authorNode = bookEle.appendChild(document.createElement("作者"));
authorNode.setTextContent(book.getAuthor());
Node priceNode = bookEle.appendChild(document.createElement("售价"));
priceNode.setTextContent(book.getPrice());
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer();
transformer.transform(new DOMSource(document), new StreamResult(uri));
}
public static void updateBook(Book book, String uri) throws Exception {
Document document = DocumentBuilderFactory.newInstance()
.newDocumentBuilder().parse(uri);
NodeList bookNodes = document.getElementsByTagName("书");
for (int i = 0; i < bookNodes.getLength(); i++) {
Element bookEle = (Element) bookNodes.item(i);
if (bookEle.getAttribute("id").equals(book.getId())) {
bookEle.setAttribute("出版社", book.getPublisher());
bookEle.getElementsByTagName("书名").item(0)
.setTextContent(book.getBookName());
bookEle.getElementsByTagName("作者").item(0)
.setTextContent(book.getAuthor());
bookEle.getElementsByTagName("售价").item(0)
.setTextContent(book.getPrice());
}
}
TransformerFactory.newInstance().newTransformer()
.transform(new DOMSource(document), new StreamResult(uri));
}
public static void deleteBook(String id, String uri) throws Exception {
Document document = DocumentBuilderFactory.newInstance()
.newDocumentBuilder().parse(uri);
NodeList bookNodes = document.getElementsByTagName("书");
for (int i = 0; i < bookNodes.getLength(); i++) {
Element bookEle = (Element) bookNodes.item(i);
if (bookEle.getAttribute("id").equals(id)) {
bookEle.getParentNode().removeChild(bookEle);
}
}
TransformerFactory.newInstance().newTransformer()
.transform(new DOMSource(document), new StreamResult(uri));
}
}
SAX解析
在使用 DOM 解析 XML 文档时,需要读取整个 XML 文档,在内存中构架代表整个 DOM 树的Doucment对象,从而再对XML文档进行操作。此种情况下,如果 XML 文档特别大,就会消耗计算机的大量内存,并且容易导致内存溢出。
SAX解析允许在读取文档的时候,即对文档进行处理,而不必等到整个文档装载完才对文档进行操作。
SAX采用事件处理的方式解析XML文件,利用 SAX 解析 XML 文档,涉及两个部分:解析器和事件处理器:
解析器可以使用JAXP的API创建,创建出SAX解析器后,就可以指定解析器去解析某个XML文档。
解析器采用SAX方式在解析某个XML文档时,它只要解析到XML文档的一个组成部分,都会去调用事件处理器的一个方法,解析器在调用事件处理器的方法时,会把当前解析到的xml文件内容作为方法的参数传递给事件处理器。
事件处理器由程序员编写,程序员通过事件处理器中方法的参数,就可以很轻松地得到sax解析器解析到的数据,从而可以决定如何对数据进行处理。
SAX方式解析XML文档
1) 使用SAXParserFactory创建SAX解析工厂
SAXParserFactory spf = SAXParserFactory.newInstance();
2) 通过SAX解析工厂得到解析器对象
SAXParser sp = spf.newSAXParser();
3) 通过解析器对象得到一个XML的读取器
XMLReader xmlReader = sp.getXMLReader();
4) 设置读取器的事件处理器
xmlReader.setContentHandler(new BookParserHandler());
5) 解析xml文件
xmlReader.parse("book.xml");
DOM4J解析XML文档
Dom4j是一个简单、灵活的开放源代码的库。Dom4j是由早期开发JDOM的人分离出来而后独立开发的。与JDOM不同的是,dom4j使用接口和抽象基类,虽然Dom4j的API相对要复杂一些,但它提供了比JDOM更好的灵活性。
Dom4j是一个非常优秀的Java XML API,具有性能优异、功能强大和极易使用的特点。现在很多软件采用的Dom4j,例如Hibernate,包括sun公司自己的JAXM也用了Dom4j。
使用Dom4j开发,需下载dom4j相应的jar文件。
DOM4j中,获得Document对象的方式有三种:
1.读取XML文件,获得document对象
SAXReader reader = new SAXReader();
Document document = reader.read(new File("input.xml"));
2.解析XML形式的文本,得到document对象.
String text = "<members></members>";
Document document = DocumentHelper.parseText(text);
3.主动创建document对象.
Document document = DocumentHelper.createDocument();
//创建根节点
Element root = document.addElement("members");
SAX解析代码实例
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import com.itheima.domain.Book;
public class SAXUtil {
private static Book book = null;
private static List<Book> books = new ArrayList<Book>();
public static List<Book> getBooks(String uri) throws Exception {
// 首先 获得 一个 工厂 对象
SAXParserFactory factory = SAXParserFactory.newInstance();
// 通过工厂对象 整出 一个 解析器对象
SAXParser parser = factory.newSAXParser();
// 拿到 一个 xml reader 对象.
XMLReader xmlReader = parser.getXMLReader();
// 提前设置 好 事件 处理器
xmlReader.setContentHandler(new DefaultHandler() {
String temp = null;
@Override
public void startElement(String uri, String localName,
String qName, Attributes attributes) throws SAXException {
super.startElement(uri, localName, qName, attributes);
if ("书".equals(qName)) {
book = new Book();
book.setId(attributes.getValue("id"));
book.setPublisher(attributes.getValue("出版社"));
}
else if ("书名".equals(qName))
temp = "书名";
else if ("作者".equals(qName))
temp = "作者";
else if ("售价".equals(qName))
temp = "售价";
}
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
super.characters(ch, start, length);
if ("书名".equals(temp))
book.setBookName(new String(ch, start, length));
else if ("作者".equals(temp))
book.setAuthor(new String(ch, start, length));
else if ("售价".equals(temp))
book.setPrice(new String(ch, start, length));
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
super.endElement(uri, localName, qName);
if ("书".equals(qName)) {
books.add(book);
book = null;
}
temp = null;
}
});
// 解析xml文件.
xmlReader.parse(uri);
return books;
}
}
pull 解析器
pull 解析器是一个第三方的开源api,其解析原理与sax 解析原理很相像,都是采用事件驱动的方式.
不同点: pull 解析器在每次读取到一段数据之后,需要程序员手动的调用其next() 方法,将当前解析到的这一行的"指针"移到下一行.
http://kxml.sourceforge.net/kxml2/
在目前的android 平台中解析xml 文件都是采用pull解析器,是谷歌力推的xml解析器
pull 解析器是一个开源的java项目,既可以用于android,也可以用于JavaEE。
在android源码根目录的libcore目录下存放的是pull 解析器相关的所有类库.
pull 解析代码实例
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserFactory;
import org.xmlpull.v1.XmlSerializer;
import com.itheima.domain.Book;
public class PullUtil {
public static List<Book> getBooks(String uri) throws Exception {
// 通过 xmlpull parser 工厂整出 一个 工厂 对象.
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
// 拿到 一个解析器 对象 .
XmlPullParser parser = factory.newPullParser();
// 设置要解析的 xml文件 .
parser.setInput(new FileInputStream(uri), "UTF-8");
// 获得 eventtype (事件 类型 )
int eventType = parser.getEventType();
// 启动 一个 循环 去 一行行 读取 xml文件.
Book book = null;
List<Book> books = new ArrayList<Book>();
while (eventType != XmlPullParser.END_DOCUMENT) {
switch (eventType) {
case XmlPullParser.START_TAG:
if ("书".equals(parser.getName())) {
book = new Book();
for (int i = 0; i < parser.getAttributeCount(); i++) {
if ("id".equals(parser.getAttributeName(i)))
book.setId(parser.getAttributeValue(i));
if ("出版社".equals(parser.getAttributeName(i)))
book.setPublisher(parser.getAttributeValue(i));
}
}
if ("书名".equals(parser.getName()))
book.setBookName(parser.nextText());
if ("作者".equals(parser.getName()))
book.setAuthor(parser.nextText());
if ("售价".equals(parser.getName()))
book.setPrice(parser.nextText());
break;
case XmlPullParser.END_TAG:
if ("书".equals(parser.getName())) {
books.add(book);
}
break;
default:
break;
}
eventType = parser.next();
}
return books;
}
public static void addBooks(List<Book> books, String uri) throws Exception {
XmlSerializer serializer = XmlPullParserFactory.newInstance()
.newSerializer();
FileOutputStream fileOutputStream = new FileOutputStream(uri);
serializer.setOutput(fileOutputStream, "UTF-8");
serializer.startDocument("UTF-8", true);
serializer.startTag(null, "书架");
for (Book book : books) {
serializer.startTag(null, "书");
serializer.attribute(null, "id", book.getId());
serializer.attribute(null, "出版社", book.getPublisher());
serializer.startTag(null, "书名");
serializer.text(book.getBookName());
serializer.endTag(null, "书名");
serializer.startTag(null, "作者");
serializer.text(book.getAuthor());
serializer.endTag(null, "作者");
serializer.startTag(null, "售价");
serializer.text(book.getPrice());
serializer.endTag(null, "售价");
serializer.endTag(null, "书");
}
serializer.endTag(null, "书架");
serializer.endDocument();
fileOutputStream.flush();
fileOutputStream.close();
}
}
DOM4J是dom4j.org出品的一个开源XML解析包。Dom4j是一个易用的、开源的库,用于XML,XPath和XSLT。它应用于Java平台,采用了Java集合框架并完全支持DOM,SAX和JAXP。
dom4j 代码实例
package com.itheima.util;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import com.itheima.domain.Book;
public class Dom4jUtil {
public static List<Book> getBooks(String uri) throws Exception {
List<Book> books = new ArrayList<Book>();
Book book = null;
SAXReader reader = new SAXReader();
Document document = reader.read(new FileInputStream(uri));
Element rootEle = document.getRootElement();
for (Iterator<Element> i = rootEle.elementIterator("书"); i.hasNext();) {
Element bookEle = i.next();
book = new Book();
book.setId(bookEle.attributeValue("id"));
book.setPublisher(bookEle.attributeValue("出版社"));
book.setBookName(bookEle.elementText("书名"));
book.setAuthor(bookEle.elementText("作者"));
book.setPrice(bookEle.elementText("售价"));
books.add(book);
book = null;
}
return books;
}
public static void addBook(Book book, String uri) throws Exception {
SAXReader reader = new SAXReader();
Document document = reader.read(new FileInputStream(uri));
Element rootEle = document.getRootElement();
Element bookEle = rootEle.addElement("书")
.addAttribute("id", book.getId())
.addAttribute("出版社", book.getPublisher());
bookEle.addElement("书名").addText(book.getBookName());
bookEle.addElement("作者").addText(book.getAuthor());
bookEle.addElement("售价").addText(book.getPrice());
OutputFormat format = OutputFormat.createPrettyPrint();
format.setEncoding("UTF-8");
XMLWriter writer = new XMLWriter(new FileOutputStream(uri), format);
writer.write(document);
writer.close();
}
public static void deleteBook(String id, String uri) throws Exception {
SAXReader reader = new SAXReader();
Document document = reader.read(new FileInputStream(uri));
Element rootEle = document.getRootElement();
for (Iterator<Element> i = rootEle.elementIterator("书"); i.hasNext();) {
Element bookEle = i.next();
if (bookEle.attributeValue("id").equals(id))
rootEle.remove(bookEle);
}
OutputFormat format = OutputFormat.createPrettyPrint();
format.setEncoding("UTF-8");
XMLWriter writer = new XMLWriter(new FileOutputStream(uri), format);
writer.write(document);
writer.close();
}
public static void updateBook(Book book, String uri) throws Exception {
SAXReader reader = new SAXReader();
Document document = reader.read(new FileInputStream(uri));
Element rootEle = document.getRootElement();
for (Iterator<Element> i = rootEle.elementIterator("书"); i.hasNext();) {
Element bookEle = i.next();
if (bookEle.attributeValue("id").equals(book.getId())) {
bookEle.attribute("出版社").setValue(book.getPublisher());
bookEle.element("书名").setText(book.getBookName());
bookEle.element("作者").setText(book.getAuthor());
bookEle.element("售价").setText(book.getPrice());
}
OutputFormat format = OutputFormat.createPrettyPrint();
format.setEncoding("UTF-8");
XMLWriter writer = new XMLWriter(new FileOutputStream(uri), format);
writer.write(document);
writer.close();
}
}
}