XML解析在Android中应用的比较多,很多时候存储数据需要使用到XML。
这里介绍四种XML解析方式,很多地方说是三种xml解析方式(除去第一种原生xml解析),但是这里的XmlResourceParser跟其他三种不知道是否重复:
1、原生XML解析:XmlResourceParser
2、SAX解析器,
3、DOM解析器,
4、PULL解析器
公共接口:
public interface BookParser {
//解析输入流,得到book对象集合
public List<Book> parse(InputStream is) throws Exception;
//序列化Book对象集合,得到xml形式字符串
public String serialize(List<Book> books) throws Exception;
}
公共实体类:
package com.mfc.xmlutils;
/**
* Created by Administrator on 2017/8/11.
*/
public class Book {
private int id;
private String name;
private float price;
public Book() {
}
public Book(int id, String name, float price) {
this.id = id;
this.name = name;
this.price = price;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
@Override
public String toString() {
return "Book{" +
"id=" + id +
", name='" + name + '\'' +
", price=" + price +
'}';
}
}
一、原生XML解析:XmlResourceParser
books.xml:(这个xml存放在res的xml文件夹里):
<?xml version="1.0" encoding="utf-8"?>
<books>
<book price="1.0" id="1001">Java</book>
<book price="89.0" id="1002">Java EE</book>
<book price="69.0" id="1003">Ajax</book>
</books>
工具类:
package com.mfc.xmlutils;
import android.content.Context;
import android.content.res.XmlResourceParser;
import com.example.administrator.parsexml.R;
import java.util.ArrayList;
import java.util.List;
public class XmlResourceParserUtil {
private Context context;
public XmlResourceParserUtil(Context context){
this.context = context;
}
public List<Book> getXmlResource(){
XmlResourceParser xlp = context.getResources().getXml(R.xml.books);
try {
List<Book> books = new ArrayList<Book>();
Book book = null;
//循环,如果还没有到xml文档的结尾处
while (xlp.getEventType() != XmlResourceParser.END_DOCUMENT){
//如果遇到了开始标签
if (xlp.getEventType() == XmlResourceParser.START_TAG){
//获取标签名
String tagName = xlp.getName();
//如果遇到Book标签
if (tagName.equals("book")){
book = new Book();
//根据属性名来获取属性值
String bookPrice = xlp.getAttributeValue(0);
book.setPrice(Float.parseFloat(bookPrice));
String id = xlp.getAttributeValue(1);
book.setId(Integer.parseInt(id));
//获取文本节点的值
book.setName(xlp.nextText());
books.add(book);
}
}
xlp.next();
}
return books;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
activity:
parserButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
XmlResourceParserUtil xmlResourceParserUtil = new XmlResourceParserUtil(SAXParserXmlActivity.this);
List<Book> books = xmlResourceParserUtil.getXmlResource();
StringBuilder stringBuilder = new StringBuilder();
for (Book book : books) {
stringBuilder.append(book.toString());
}
XMLContent.setText(stringBuilder.toString());
}
});
二、SAX解析器:
books.xml(这个xml存放在assets文件夹下):以下几种解析xml的方法都使用的这一个xml
<?xml version="1.0" encoding="utf-8"?>
<books>
<book>
<id>1001</id>
<name>java编程思想</name>
<price>80.00</price>
</book>
<book>
<id>1002</id>
<name>Android群英传</name>
<price>90.00</price>
</book>
<book>
<id>1003</id>
<name>spring源码解析</name>
<price>100.00</price>
</book>
</books>
工具类:
package com.mfc.xmlutils;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
import org.xml.sax.helpers.DefaultHandler;
import java.io.InputStream;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
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.TransformerFactory;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stream.StreamResult;
/**
* Created by Administrator on 2017/8/11.
*/
public class BookSaxParser implements BookParser {
@Override
public List<Book> parse(InputStream is) throws Exception {
//取得SAXParserFactory实例
SAXParserFactory factory = SAXParserFactory.newInstance();
//从factory获取SAXParser实例
SAXParser parser = factory.newSAXParser();
//实例化自定义的Handler
MyHandler myHandler = new MyHandler();
parser.parse(is,myHandler);
return myHandler.getBooks();
}
@Override
public String serialize(List<Book> books) throws Exception {
//取得SAXTransformerFactory实例
SAXTransformerFactory factory = (SAXTransformerFactory) TransformerFactory.newInstance();
//从factory获取TransformerHandler实例
TransformerHandler handler = factory.newTransformerHandler();
//从handler获取Transformer实例
Transformer transformer = handler.getTransformer();
//设置输出采用的编码方式
transformer.setOutputProperty(OutputKeys.ENCODING,"UTF-8");
//是否自动添加额外的空白
transformer.setOutputProperty(OutputKeys.INDENT,"yes");
//是否忽略xml声明
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION,"no");
StringWriter writer = new StringWriter();
Result result = new StreamResult(writer);
handler.setResult(result);
//代表命名空间的URI,当URI无值时,需设置为空字符串
String uri = "";
//命名空间的本地名称(不包含前缀),当没有进行命名空间处理时,需要设置为空字符串
String localName = "";
handler.startDocument();;
handler.startElement(uri,localName,"books",null);
//负责存放元素的属性信息
AttributesImpl attrs = new AttributesImpl();
char[] ch = null;
for (Book book : books){
//清空属性列表
attrs.clear();
//添加一个名为id的属性(type影响不大,这里设置为String)
attrs.addAttribute(uri,localName,"id","string",String.valueOf(book.getId()));
//开始一个book元素,关联上面设定的id属性
handler.startElement(uri,localName,"book",attrs);
//开始一个那么属性,没有元素
handler.startElement(uri,localName,"name",null);
ch = String.valueOf(book.getName()).toCharArray();
//设置price元素的文本节点
handler.characters(ch,0,ch.length);
handler.endElement(uri,localName,"price");
handler.endElement(uri,localName,"book");
}
handler.endElement(uri,localName,"books");
handler.endDocument();
return writer.toString();
}
//需要重写DefaultHandler的方法
private class MyHandler extends DefaultHandler{
private List<Book> books;
private Book book;
private StringBuilder builder;
//返回解析后得到的Book对象集合
public List<Book> getBooks() {
return books;
}
//初始化
@Override
public void startDocument() throws SAXException {
super.startDocument();
books = new ArrayList<Book>();
builder = new StringBuilder();
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
super.startElement(uri, localName, qName, attributes);
//开始如果遇到了book标签,就新建一个Book对象
if (localName.equals("book")) {
book = new Book();
}
//将字符长度设置为0,一边重新开始读取元素的字符节点
builder.setLength(0);
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
super.characters(ch, start, length);
//将读取的字符数组追加到builder中
builder.append(ch,start,length);
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
super.endElement(uri, localName, qName);
//遇到book标签后,接下来将遇到的标签对应的值放进实体类对应的属性里面
if (localName.equals("id")){
book.setId(Integer.parseInt(builder.toString()));
}else if (localName.equals("name")) {
book.setName(builder.toString());
}else if (localName.equals("price")) {
book.setPrice(Float.parseFloat(builder.toString()));
}else if (localName.equals("book")) {
books.add(book);
}
}
}
}
activity:
parserXmlBySAXButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
InputStream is = getAssets().open("books.xml");
//创建SaxBookParser实例
parserSAX = new BookSaxParser();
//解析输入流
books = parserSAX.parse(is);
StringBuilder stringBuilder = new StringBuilder();
for (Book book : books) {
stringBuilder.append(book.toString());
}
XMLContent.setText(stringBuilder.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
});
writerXmlBySAXButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
String xml = parserSAX.serialize(books);
FileOutputStream fos = openFileOutput("books.xml", Context.MODE_PRIVATE);
fos.write(xml.getBytes("UTF-8"));
Toast.makeText(SAXParserXmlActivity.this, "写入成功",Toast.LENGTH_LONG).show();
} catch (Exception e) {
e.printStackTrace();
}
}
});
三、DOM解析器:
工具类:
package com.mfc.xmlutils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import java.io.InputStream;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
/**
* Created by Administrator on 2017/8/12.
*/
public class BookDomParser implements BookParser {
@Override
public List<Book> parse(InputStream is) throws Exception {
List<Book> books = new ArrayList<Book>();
//获取DocumentBuilderFactory实例
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
//从factory获取DocumentBuilder实例
DocumentBuilder builder = factory.newDocumentBuilder();
//解析输入流,得到Document实例
Document doc = builder.parse(is);
Element rootElement = doc.getDocumentElement();
NodeList items = rootElement.getElementsByTagName("book");
for (int i=0;i<items.getLength();i++) {
Book book = new Book();
Node item = items.item(i);
NodeList properties = item.getChildNodes();
for (int j = 0;j<properties.getLength();j++) {
Node property = properties.item(j);
String nodeName = property.getNodeName();
if(nodeName.equals("id")){
book.setId(Integer.parseInt(property.getFirstChild().getNodeValue()));
} else if (nodeName.equals("name")) {
book.setName(property.getFirstChild().getNodeValue());
} else if (nodeName.equals("price")) {
book.setPrice(Float.parseFloat(property.getFirstChild().getNodeValue()));
}
}
books.add(book);
}
return books;
}
@Override
public String serialize(List<Book> books) throws Exception {
//获取DocumentBuilderFactory对象
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
//由builder创建新文档
Document doc = builder.newDocument();
Element rootElement = doc.createElement("books");
for (Book book : books) {
Element bookElement = doc.createElement("book");
bookElement.setAttribute("id",book.getId()+"");
Element nameElement = doc.createElement("name");
nameElement.setTextContent(book.getName());
bookElement.appendChild(nameElement);
Element priceElement = doc.createElement("price");
priceElement.setTextContent(book.getPrice()+"");
bookElement.appendChild(priceElement);
rootElement.appendChild(bookElement);
}
doc.appendChild(rootElement);
//取得TransformerFactory实例
TransformerFactory transFactory = TransformerFactory.newInstance();
//从transFactory获取Transformer实例
Transformer transformer = transFactory.newTransformer();
//设置输出采用的编码方式
transformer.setOutputProperty(OutputKeys.ENCODING,"UTF-8");
//设置自动添加额外的空白
transformer.setOutputProperty(OutputKeys.INDENT,"yes");
//设置忽略xml声明
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION,"no");
StringWriter writer = new StringWriter();
//表明文档来源是doc
Source source = new DOMSource(doc);
//表明目标结果为writer
Result result = new StreamResult(writer);
//开始转换
transformer.transform(source,result);
return writer.toString();
}
}
activity:
parserXmlByDOMButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
InputStream is = getAssets().open("books.xml");
//创建SaxBookParser实例
parserDOM = new BookDomParser();
//解析输入流
books = parserDOM.parse(is);
StringBuilder stringBuilder = new StringBuilder();
for (Book book : books) {
stringBuilder.append(book.toString());
}
XMLContent.setText(stringBuilder.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
});
writerXmlByDOMButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
String xml = parserDOM.serialize(books);
FileOutputStream fos = openFileOutput("books.xml", Context.MODE_PRIVATE);
fos.write(xml.getBytes("UTF-8"));
Toast.makeText(SAXParserXmlActivity.this, "写入成功",Toast.LENGTH_LONG).show();
} catch (Exception e) {
e.printStackTrace();
}
}
});
四、PULL解析器
工具类:package com.mfc.xmlutils;
import android.util.Xml;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlSerializer;
import java.io.InputStream;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Administrator on 2017/8/12.
*/
public class BookPullParser implements BookParser {
@Override
public List<Book> parse(InputStream is) throws Exception {
List<Book> books = null;
Book book = null;
//从android.util.Xml创建一个XmlPullParser实例
XmlPullParser parser = Xml.newPullParser();
//设置输入流,并指明编码方式
parser.setInput(is,"UTF-8");
int eventType = parser.getEventType();
while(eventType != XmlPullParser.END_DOCUMENT){
switch (eventType){
case XmlPullParser.START_DOCUMENT:
books = new ArrayList<Book>();
break;
case XmlPullParser.START_TAG:
if (parser.getName().equals("book")) {
book = new Book();
}else if (parser.getName().equals("id")){
eventType = parser.next();
book.setId(Integer.parseInt(parser.getText()));
}else if (parser.getName().equals("name")){
eventType = parser.next();
book.setName(parser.getText());
}else if (parser.getName().equals("price")){
eventType = parser.next();
book.setPrice(Float.parseFloat(parser.getText()));
}
break;
case XmlPullParser.END_TAG:
if (parser.getName().equals("book")){
books.add(book);
book = null;
}
break;
}
eventType = parser.next();
}
return books;
}
@Override
public String serialize(List<Book> books) throws Exception {
//由android.util.Xml创建一个XmlSerializer实例
XmlSerializer serializer = Xml.newSerializer();
StringWriter writer = new StringWriter();
//设置输出方式为writer
serializer.setOutput(writer);
serializer.startDocument("UTF-8",true);
serializer.startTag("","books");
for (Book book : books) {
serializer.startTag("","book");
serializer.attribute("","id",book.getId()+"");
serializer.startTag("","name");
serializer.text(book.getName());
serializer.endTag("","name");
serializer.startTag("", "price");
serializer.text(book.getPrice() + "");
serializer.endTag("", "price");
serializer.endTag("", "book");
}
serializer.endTag("", "books");
serializer.endDocument();
return writer.toString();
}
}
activity:
parserXmlByPULLButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
InputStream is = getAssets().open("books.xml");
//创建SaxBookParser实例
parserPULL = new BookDomParser();
//解析输入流
books = parserPULL.parse(is);
StringBuilder stringBuilder = new StringBuilder();
for (Book book : books) {
stringBuilder.append(book.toString());
}
XMLContent.setText(stringBuilder.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
});
writerXmlByPULLButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
String xml = parserPULL.serialize(books);
FileOutputStream fos = openFileOutput("books.xml", Context.MODE_PRIVATE);
fos.write(xml.getBytes("UTF-8"));
Toast.makeText(SAXParserXmlActivity.this, "写入成功",Toast.LENGTH_LONG).show();
} catch (Exception e) {
e.printStackTrace();
}
}
});
效果图(这里由于使用的真机,所以看不到写入的文件):
对于这几种解析器各有优点,更倾向于PULL解析器,因为SAX解析器操作起来太笨重,DOM不适合文档较大,内存较小的场景,唯有PULL轻巧灵活,速度快,占用内存小,使用非常顺手。
源码下载:http://download.csdn.net/download/fancheng614/9931088