在Android中,Xml有三种解析方式,对应也有三种创建方式,分别是Dom解析,Pull解析,Sax解析。
1.Dom解析
DOM是基于树形结构的的节点或信息片段的集合,允许开发人员使用DOM API遍历XML树、检索所需数据。分析该结构通常需要加载整个文档和构造树形结构,然后才可以检索和更新节点信息。Android完全支持DOM 解析。利用DOM中的对象,可以对XML文档进行读取、搜索、修改、添加和删除等操作。
DOM的工作原理:使用DOM对XML文件进行操作时,首先要解析文件,将文件分为独立的元素、属性和注释等,然后以节点树的形式在内存中对XML文件进行表示,就可以通过节点树访问文档的内容,并根据需要修改文档——这就是DOM的工作原理。
DOM实现时首先为XML文档的解析定义一组接口,解析器读入整个文档,然后构造一个驻留内存的树结构,这样代码就可以使用DOM接口来操作整个树结构。
由于DOM在内存中以树形结构存放,因此检索和更新效率会更高。但是对于特别大的文档,解析和加载整个文档将会很耗资源。 当然,如果XML文件的内容比较小,采用DOM是可行的。
常用的DoM接口和类:
Document:该接口定义分析并创建DOM文档的一系列方法,它是文档树的根,是操作DOM的基础。
Element:该接口继承Node接口,提供了获取、修改XML元素名字和属性的方法。
Node:该接口提供处理并获取节点和子节点值的方法。
NodeList:提供获得节点个数和当前节点的方法。这样就可以迭代地访问各个节点。
DOMParser:该类是Apache的Xerces中的DOM解析器类,可直接解析XML文件。
DocumentBuilderFactory:单例类,是一个工厂类;
DocumentBuilder: Document构建类
DomParseTool类
package factory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import bean.Book;
/**
* Created by John on 2016/12/4.
*/
public class DomParseTool extends XMLParseFactory {
List<Book> bookList;
DocumentBuilderFactory factory;
DocumentBuilder builder;
public DomParseTool() {
bookList = new ArrayList<Book>();
factory = DocumentBuilderFactory.newInstance();
try {
builder = factory.newDocumentBuilder();
} catch (ParserConfigurationException e) {
e.printStackTrace();
}
}
@Override
public void readXML(InputStream mInputStream) {
try {
Document document = builder.parse(mInputStream);
Element element = document.getDocumentElement();
NodeList nodeList = element.getElementsByTagName(Book.BOOK);
for (int i = 0; i < nodeList.getLength(); i++) {
Element ele = (Element) nodeList.item(i);
Book book = new Book();
book.setId(Integer.valueOf(ele.getAttribute(Book.ID)));
NodeList childNodeList = ele.getChildNodes();
for (int j = 0; j < childNodeList.getLength(); j++) {
Node childNode = childNodeList.item(j);
if (childNode.getNodeType() == Node.ELEMENT_NODE) {
if (Book.NAME.equals(childNode.getNodeName())) {
book.setName(childNode.getFirstChild().getNodeValue());
} else if (Book.PRICE.equals(childNode.getNodeName())) {
book.setPrice(Float.valueOf(childNode.getFirstChild().getNodeValue()));
}
}
}
bookList.add(book);
}
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void writeXML(String filePath) {
}
@Override
public void writeXML(String filePath,List<Book> mBooks) {
String str = filePath;
Document doc = builder.newDocument();
Element rootele = doc.createElement(Book.BOOKS);
doc.appendChild(rootele);
for (int i = 0; i < mBooks.size(); i++) {
Book book = mBooks.get(i);
Element bookEle = doc.createElement(Book.BOOK);
bookEle.setAttribute(Book.ID, String.valueOf(book.getId()));
Element nameEle = doc.createElement(Book.NAME);
nameEle.appendChild(doc.createTextNode(book.getName()));
bookEle.appendChild(nameEle);
Element priceEle = doc.createElement(Book.PRICE);
priceEle.appendChild(doc.createTextNode(String.valueOf(book.getPrice())));
bookEle.appendChild(priceEle);
rootele.appendChild(bookEle);
}
TransformerFactory mTransformerf = TransformerFactory.newInstance();
try {
Transformer mTransformer = mTransformerf.newTransformer();
DOMSource resource = new DOMSource(doc);
mTransformer.setOutputProperty(OutputKeys.ENCODING, "utf-8");
mTransformer.setOutputProperty(OutputKeys.INDENT, "no");
try {
FileOutputStream fileOs = new FileOutputStream(filePath);
PrintWriter pw = new PrintWriter(fileOs);
StreamResult sr = new StreamResult(pw);
mTransformer.transform(resource,sr);
} catch (Exception e) {
e.printStackTrace();
}
} catch (TransformerConfigurationException e) {
e.printStackTrace();
}
}
@Override
public void setBookList(List<Book> mBookList) {
this.bookList = mBookList;
}
@Override
public List<Book> getBookList() {
return bookList;
}
}
2.Pull解析
Android并未提供对Java StAX API的支持。但是,Android附带了一个pull解析器,其工作方式类似于StAX。它允许用户的应用程序代码从解析器中获取事件,这与SAX解析器自动将事件推入处理程序相反。
PULL解析器的运行方式和SAX类似,都是基于事件的模式。不同的是,在PULL解析过程中返回的是数字,且我们需要自己获取产生的事件然后做相应的操作,而不像SAX那样由处理器触发一种事件的方法,执行我们的代码。
读取到xml的声明返回 START_DOCUMENT;
读取到xml的结束返回 END_DOCUMENT ;
读取到xml的开始标签返回 START_TAG
读取到xml的结束标签返回 END_TAG
读取到xml的文本返回 TEXT
PULL解析器小巧轻便,解析速度快,简单易用,非常适合在Android移动设备中使用,Android系统内部在解析各种XML时也是用PULL解析器,Android官方推荐开发者们使用Pull解析技术。Pull解析技术是第三方开发的开源技术,它同样可以应用于JavaSE开发。
PULL 的工作原理:XML pull提供了开始元素和结束元素。当某个元素开始时,我们可以调用parser.nextText从XML文档中提取所有字符数据。当解释到一个文档结束时,自动生成EndDocument事件。
常用的XML pull的接口和类:
XmlPullParser:XML pull解析器是一个在XMLPULL VlAP1中提供了定义解析功能的接口。
XmlSerializer:它是一个接口,定义了XML信息集的序列。
XmlPullParserFactory:这个类用于在XMPULL V1 API中创建XML Pull解析器。
XmlPullParserException:抛出单一的XML pull解析器相关的错误。
package factory;
import android.util.Xml;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import bean.Book;
public class PULLParseTool extends XMLParseFactory {
private List<Book> mBooksList;
private Book book;
@Override
public void readXML(InputStream mInputStream) {
XmlPullParser mXmlPullParser = Xml.newPullParser();
try {
mXmlPullParser.setInput(mInputStream, "UTF-8");
int parserType = mXmlPullParser.getEventType();
while (parserType!=XmlPullParser.END_DOCUMENT) {
String tagName = mXmlPullParser.getName();
switch (parserType) {
case XmlPullParser.START_DOCUMENT:
mBooksList = new ArrayList<Book>();
break;
case XmlPullParser.START_TAG:
if (Book.BOOK.equals(tagName)) {
book = new Book();
book.setId(Integer.valueOf(mXmlPullParser.getAttributeValue("", Book.ID)));
}
else if(Book.NAME.equals(tagName)){
book.setName(mXmlPullParser.nextText());
}else if(Book.PRICE.equals(tagName)){
book.setPrice(Float.valueOf(mXmlPullParser.nextText()));
}
break;
case XmlPullParser.END_TAG:
if (Book.BOOK.equals(tagName)) {
mBooksList.add(book);
}
}
parserType = mXmlPullParser.next();
}
} catch (XmlPullParserException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
if (mInputStream!=null) {
try {
mInputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
@Override
public void writeXML(String filePath) {
// TODO Auto-generated method stub
XmlSerializer mSerializer = Xml.newSerializer();
FileOutputStream fos = null;
try {
fos =new FileOutputStream(filePath);
mSerializer.setOutput(fos, "utf-8");
mSerializer.startDocument("utf-8", true);
mSerializer.startTag("",Book.BOOKS);
for (Book book: getBookList()) {
mSerializer.startTag("", Book.BOOK);
mSerializer.attribute("", Book.ID,String.valueOf(book.getId()));
mSerializer.startTag("", Book.NAME);
mSerializer.text(book.getName());
mSerializer.endTag("",Book.NAME);
mSerializer.startTag("",Book.PRICE);
mSerializer.text(String.valueOf(book.getPrice()));
mSerializer.endTag("", Book.PRICE);
mSerializer.endTag("", Book.BOOK);
}
mSerializer.endTag("", Book.BOOKS);
mSerializer.endDocument();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
if (fos!=null) {
try {
fos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
@Override
public void setBookList(List<Book> mBookList) {
if (this.mBooksList!=null&& this.mBooksList.size()>0) {
this.mBooksList.clear();
}
this.mBooksList = mBookList;
}
@Override
public List<Book> getBookList() {
// TODO Auto-generated method stub
return mBooksList;
}
}
3.Sax解析
SAX(Simple API for XML)解析器是一种基于事件的解析器,事件驱动的流式解析方式是,从文件的开始顺序解析到文档的结束,不可暂停或倒退。它的核心是事件处理模式,主要是围绕着事件源以及事件处理器来工作的。当事件源产生事件后,调用事件处理器相应的处理方法,一个事件就可以得到处理。在事件源调用事件处理器中特定方法的时候,还要传递给事件处理器相应事件的状态信息,这样事件处理器才能够根据提供的事件信息来决定自己的行为。
SAX解析器的优点是解析速度快,占用内存少。非常适合在Android移动设备中使用。
SAX的工作原理:SAX的工作原理简单地说就是对文档进行顺序扫描,当扫描到文档(document)开始与结束、元素(element)开始与结束、文档(document)结束等地方时通知事件处理函数,由事件处理函数做相应动作,然后继续同样的扫描,直至文档结束。
在SAX接口中,事件源是org.xml.sax包中的XMLReader,它通过parser()方法来解析XML文档,并产生事件。事件处理器是org.xml.sax包中ContentHander、DTDHander、ErrorHandler,以及EntityResolver这4个接口。XMLReader通过相应事件处理器注册方法setXXXX()来完成的与ContentHander、DTDHander、ErrorHandler,以及EntityResolver这4个接口的连接。
常用的SAX接口和类:
Attrbutes:用于得到属性的个数、名字和值。
ContentHandler:定义与文档本身关联的事件(例如,开始和结束标记)。大多数应用程序都注册这些事件。
DTDHandler:定义与DTD关联的事件。它没有定义足够的事件来完整地报告DTD。如果需要对DTD进行语法分析,请使用可选的DeclHandler。
DeclHandler是SAX的扩展。不是所有的语法分析器都支持它。
EntityResolver:定义与装入实体关联的事件。只有少数几个应用程序注册这些事件。
ErrorHandler:定义错误事件。许多应用程序注册这些事件以便用它们自己的方式报错。
DefaultHandler:它提供了这些接LI的缺省实现。在大多数情况下,为应用程序扩展DefaultHandler并覆盖相关的方法要比直接实现一个接口更容易。
详见下表:
可知,我们需要XmlReader 以及DefaultHandler来配合解析xml。
SaxHandler
package sax;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;import java.util.ArrayList;
import java.util.List;import bean.Book;
/**
* @author John
* Sax
*/
public class SaxHandler extends DefaultHandler{
private List<Book> mBookList;
private Book book;
private String targetElemant;
public List<Book> getBookList(){
return mBookList;
}
/* (non-Javadoc)
* @see org.xml.sax.helpers.DefaultHandler#startDocument()
*/
@Override
public void startDocument() throws SAXException {
// TODO Auto-generated method stub
super.startDocument();
mBookList = new ArrayList<Book>();
}
@Override
public void endDocument() throws SAXException {
// TODO Auto-generated method stub
super.endDocument();
}
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
// TODO Auto-generated method stub
super.startElement(uri, localName, qName, attributes);
if (qName.equals(Book.BOOK)) {
book = new Book();
book.setId(Integer.valueOf(attributes.getValue(Book.ID)));
}
targetElemant = localName;
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
// TODO Auto-generated method stub
super.endElement(uri, localName, qName);
if (qName.equals(Book.BOOK)) {
mBookList.add(book);
}
targetElemant = null;
}
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
// TODO Auto-generated method stub
super.characters(ch, start, length);
if (Book.NAME.equals(targetElemant)) {
book.setName(new String(ch,start,length));
}else if(Book.PRICE.equals(targetElemant)){
book.setPrice(Float.valueOf(new String(ch,start,length)));
}
}
}
SaxPullTool
package factory;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.util.List;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stream.StreamResult;
import bean.Book;
import sax.SaxHandler;
public class SAXParseTool extends XMLParseFactory{
private SaxHandler mHandler= new SaxHandler();
private List<Book> mBookList;
@Override
public void readXML(InputStream mInputStream) {
try {
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
parser.parse(mInputStream, mHandler);
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
if (mInputStream!=null) {
try {
mInputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
@Override
public void writeXML(String filePath,List<Book> mBooks) {
SAXTransformerFactory transFactory = (SAXTransformerFactory) SAXTransformerFactory.newInstance();
TransformerHandler mHandler = null;
try {
mHandler = transFactory.newTransformerHandler();
Transformer mTransformer = mHandler.getTransformer();
mTransformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
mTransformer.setOutputProperty(OutputKeys.INDENT, "yes");
mTransformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
FileOutputStream fos = new FileOutputStream(filePath);
OutputStreamWriter writer = new OutputStreamWriter(fos);
Result result = new StreamResult(writer);
mHandler.setResult(result);
String uri = "";
String localName = "";
mHandler.startDocument();
mHandler.startElement(uri, localName, Book.BOOKS, null);
AttributesImpl attr = new AttributesImpl();
char[] ch =null;
for(Book book:mBooks){
attr.clear();
attr.addAttribute(uri, localName, Book.ID, "String", String.valueOf(book.getId()));
mHandler.startElement(uri, localName, Book.BOOK, attr);
mHandler.startElement(uri, localName, Book.NAME, null);
ch = book.getName().toCharArray();
mHandler.characters(ch, 0, ch.length);
mHandler.endElement(uri, localName, Book.NAME);
mHandler.startElement(uri, localName, Book.PRICE, null);
ch = String.valueOf(book.getId()).toCharArray();
mHandler.characters(ch, 0, ch.length);
mHandler.endElement(uri, localName, Book.PRICE);
mHandler.endElement(uri, localName, Book.BOOK);
}
mHandler.endElement(uri, localName, Book.BOOKS);
mHandler.endDocument();
} catch (TransformerConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch(FileNotFoundException e){
e.printStackTrace();
}catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void setBookList(List<Book> mBookList) {
if (this.mBookList!=null && this.mBookList.size()>0) {
this.mBookList.clear();
}
this.mBookList = mBookList;
}
@Override
public List<Book> getBookList() {
// TODO Auto-generated method stub
return mHandler.getBookList();
}
@Override
public void writeXML(String filePath) {
// TODO Auto-generated method stub
}
}
xml文件
<?xml version="1.0" encoding="utf-8"?>
<books>
<book id="1001">
<name>Thinking In Java</name>
<price>80.0</price>
</book>
<book id="1002">
<name>Core Java</name>
<price>90.0</price>
</book>
<book id="1003">
<name>Hello, Andriod</name>
<price>100.0</price>
</book>
</books>
总结:
Dom解析是将xml文件以树形结构存放在内存中
优点:检索和更新效率会更高,解析速度快
缺点:解析和加载整个文档将会很耗资源,占用内存较多,不适合用于移动平台。如果XML文件的内容比较小,采用DOM是可行的
Pull解析是一个用于处理XML事件驱动的“推”模型
优点:解析速度快,占用内存少。它是从需求出发,根据用户需要的数据进行文件的加载和解析;
缺点:不能记录标签之间的关系,让你的应用程序自己处理,这样就增加了你程序的负担
SPull解析和ax解析类似, 解析器小巧轻便,解析速度快,简单易用,非常适合在Android移动设备中使用,Android系统内部在解析各种XML时也是用PULL解析器,Android官方推荐开发者们使用Pull解析技术。Pull相比Sax,他可以控制解析的结束。