Android SAX、DOM、Pull解析xml文件剖析与案例讲解(工具类FastXmlSerializer)
XML介绍
XML(Extensible Markup Language) 即可扩展标记语言,与HTML一样,都是SGML(Standard Generalized Markup Language,标准通用标记语言)。XML是跨平台的,依赖于内容的技术,是当前处理结构化文档信息的有利工具。扩展标记语言XML是一种简单的数据存储语言,使用一系列简单的标记描述数据,而这些标记可以用方便的方式建立,虽然XML占用的空间比二进制数据要占用更多的空间,但XML简单且易于使用。
由于XML扩展性强,致使它需要稳定的基础规则来支持扩展。XML语言规则:
- 起始和结束的标签相匹配
- 嵌套标签不能相互嵌套
- 区分大小写
一、使用SAX解析XML
SAX使用流式处理的方式,当遇到一个标签时,它并不会记录下以前所碰到的标签,也就是说,在startElement()方法中,你所知道的信息,仅仅是当前标签的名字和属性,至于标签的嵌套结构,上层标签的名字,是否有子元素等其他与结构相关的信息,都是不知道的,都需要通过编码来完成。
SAX进行XML解析的整个过程:
SAXParserHandler: ***startDocument()***
SAXParserHandler: startElement uri: localName:persons qName:persons
SAXParserHandler: persons***startElement()***
SAXParserHandler: startElement uri: localName:person qName:person
SAXParserHandler: attributeName:id attributeValue:23
SAXParserHandler: person***startElement()***
SAXParserHandler: startElement uri: localName:name qName:name
SAXParserHandler: name***startElement()***
SAXParserHandler: content: zhangsan
SAXParserHandler: name***endElement()***
SAXParserHandler: startElement uri: localName:age qName:age
SAXParserHandler: age***startElement()***
SAXParserHandler: content: 21
SAXParserHandler: age***endElement()***
SAXParserHandler: person***endElement()***
SAXParserHandler: startElement uri: localName:person qName:person
SAXParserHandler: attributeName:id attributeValue:20
SAXParserHandler: person***startElement()***
SAXParserHandler: startElement uri: localName:name qName:name
SAXParserHandler: name***startElement()***
SAXParserHandler: content: wagnwu
SAXParserHandler: name***endElement()***
SAXParserHandler: startElement uri: localName:age qName:age
SAXParserHandler: age***startElement()***
SAXParserHandler: content: 25
SAXParserHandler: age***endElement()***
SAXParserHandler: person***endElement()***
SAXParserHandler: persons***endElement()***
SAXParserHandler: ***endDocument()***
从上面Log打印的信息可以了解到SAX解析XML的整个过程和顺序。
为简化工作,SAX为DefaultHandler类提供了接口的默认实现,在大多数情况下,为应用程序扩展DefaultHandler并覆盖相关的方法要比直接实现一个接口更容易。
SAX解析xml案例:
1. 创建Android XMLParser工程
2. 创建SAXParserHandler类:
复写方法:startDocument、startElement、characters、endElement、endDocument
3.Person实体类
package com.xml.demo;
public class Person {
private Integer id;
private String name;
private Short age;
public Person() {
}
public Person(Integer id, String name, Short age) {
this.id = id;
this.name = name;
this.age = age;
}
public Person(String name, Short age) {
this.name = name;
this.age = age;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Short getAge() {
return age;
}
public void setAge(Short age) {
this.age = age;
}
@Override
public String toString() {
return "id=" + id + ",name=" + name + ",age=" + age;
}
}
4 .assets\test.xml
<?xml version="1.0" encoding="UTF-8"?>
<persons>
<person id = "23">
<name>zhangsan</name>
<age>21</age>
</person>
<person id = "20">
<name>wangwu</name>
<age>25</age>
</person>
</persons>
5. SAXParserHandler类:
package com.xml.demo.sax;
import java.util.ArrayList;
import java.util.List;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import android.util.Log;
import com.xml.demo.Person;
public class SAXParserHandler extends DefaultHandler {
private static final String TAG = "SAXParserHandler";
private List<Person> persons;
private String perTag;// 通过此变量,记录前一个标签的名称。
Person person;// 记录当前Person
public List<Person> getPersons() {
return persons;
}
// 该函数只在开始解析文档时执行一次,比较适合处理一些初始化的行为
public void startDocument() throws SAXException {
persons = new ArrayList<Person>();
Log.i(TAG, "***startDocument()***");
}
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
Log.i(TAG, "startElement uri:" + uri + " localName:" + localName + " qName:" + qName);
if ("person".equals(localName)) {
for (int i = 0; i < attributes.getLength(); i++) {
Log.i(TAG, "attributeName:" + attributes.getLocalName(i) + " attributeValue:" + attributes.getValue(i));
person = new Person();
person.setId(Integer.valueOf(attributes.getValue(i)));
}
}
perTag = localName;
Log.i(TAG, qName + "***startElement()***");
}
public void characters(char[] ch, int start, int length) throws SAXException {
String data = new String(ch, start, length).trim();
if (!"".equals(data.trim())) {
Log.i(TAG, "content: " + data.trim());
}
if ("name".equals(perTag)) {
person.setName(data);
} else if ("age".equals(perTag)) {
person.setAge(new Short(data));
}
}
public void endElement(String uri, String localName, String qName) throws SAXException {
Log.i(TAG, qName + "***endElement()***");
if ("person".equals(localName)) {
persons.add(person);
person = null;
}
perTag = null;
}
public void endDocument() throws SAXException {
Log.i(TAG, "***endDocument()***");
}
}
6.MainActivity类:
package com.xml.demo;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.SAXException;
import android.app.Activity;
import android.content.res.AssetManager;
import android.os.Bundle;
import android.util.Log;
import com.xml.demo.sax.SAXParserHandler;
public class MainActivity extends Activity {
String TAG = "ZZMainActivity";
private AssetManager mAssetManager;
private InputStream mInputStream;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mAssetManager = getApplicationContext().getAssets();
try {
mInputStream = mAssetManager.open("test.xml");
} catch (IOException e) {
e.printStackTrace();
}
testSAXParser();
}
private void testSAXParser() {
SAXParserHandler saxForHandler = new SAXParserHandler();
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser saxParser = null;
try {
saxParser = spf.newSAXParser();
saxParser.parse(mInputStream, saxForHandler);
List<Person> persons = saxForHandler.getPersons();
for (Person person : persons) {
Log.i(TAG, person.toString());
}
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
SAX以流的方式接收指定的XML内容。通过上面SAX解析过程,要清楚,遇到哪些字符,会触发哪些事件,触发的顺序又是怎么样。
二、使用DOM解析XML(不推荐使用)
DOX 是一种用于XML文档的对象模型,可用于直接访问XML文档的各个部分。没有涉及回调和复杂的状态管理,然后,DOM实现常常将所有XML节点保存到内存中,这使较大的文档效率低下。
通过DOM将XML文档作为一个树形结构,这种树形街结构也被称为节点树
DOM是这样规定的:
- 整个文档是一个文档节点;
- 每个XML元素标签是一个元素节点;
- 包含在XML元素中的文本是文本节点;
- 每一个XML属性是一个属性节点;
- 注释属于注释节点。
节点树中的节点之间彼此都有等级关系。
在节点树中,顶端的节点成为根节点;
根节点之外的每个节点都有一个父节点;
节点可以有任何数量的子节点;
叶子是没有子节点的节点;
同级节点是拥有相同父节点的节点。
示例:
1. DOMParserHandler
package com.xml.demo.dom;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import com.xml.demo.Person;
public class DOMParserHandler {
private static final String TAG = "DOMParserHandler";
public static List<Person> getPersons(InputStream inStream) throws Exception {
List<Person> persons = new ArrayList<Person>();
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(inStream);
Element root = document.getDocumentElement();
NodeList personNodes = root.getElementsByTagName("person");
for (int i = 0; i < personNodes.getLength(); i++) {
Element personElement = (Element) personNodes.item(i);
int id = Integer.valueOf(personElement.getAttribute("id"));
Person person = new Person();
person.setId(id);
NodeList childNodes = personElement.getChildNodes();
for (int y = 0; y < childNodes.getLength(); y++) {
if (childNodes.item(y).getNodeType() == Node.ELEMENT_NODE) {
if ("name".equals(childNodes.item(y).getNodeName())) {
String name = childNodes.item(y).getFirstChild().getNodeValue();
person.setName(name);
} else if ("age".equals(childNodes.item(y).getNodeName())) {
String age = childNodes.item(y).getFirstChild().getNodeValue();
person.setAge(new Short(age));
}
}
}
persons.add(person);
}
inStream.close();
return persons;
}
}
2.
package com.xml.demo;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import android.app.Activity;
import android.content.res.AssetManager;
import android.os.Bundle;
import android.util.Log;
import com.xml.demo.dom.DOMParserHandler;
public class MainActivity extends Activity {
String TAG = "ZZMainActivity";
private AssetManager mAssetManager;
private InputStream mInputStream;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mAssetManager = getApplicationContext().getAssets();
try {
mInputStream = mAssetManager.open("test.xml");
} catch (IOException e) {
e.printStackTrace();
}
testDOMParser();
}
private void testDOMParser() {
try {
List<Person> persons = DOMParserHandler.getPersons(mInputStream);
for (Person person : persons) {
Log.i(TAG, person.toString());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
三、使用PULL解析XML(推荐使用这种方式)
PULL是Android系统内置的解析器,但不仅限于Android使用
Pull解析器的运行方式和SAX解析器相似。它提供了类似的事件,如开始元素和结束元素事件。使用parser.next()可以进入下一个元素并触发相应事件。事件将作为数值代码被发送,因此可以使用一个switch对感兴趣的事件进行选择,然后进行相应处理。当元素开始解析时,调用parser.nextText()方法可以获取下一个Text类型元素的值。
Pull解析器只有一个重要的方法next();它被用来检索下一个事件。而它的事件也仅仅只有5个:
-
START_DOCUMENT(开始解析)
-
START_TAG(开始元素)
-
TEXT(解析文本)
-
END_TAG(结束元素)
-
END_DOCUMENT(结束解析)
解析XML内容的方式与SAX是相似的,同样包括开始元素和结束元素事件,使用parser.next()可以进入下一个元素并触发相应事件。但是他们不同的是,SAX的事件驱动是回调相应方法,需要提供回调的方法,而后在SAX内部自动调用相应的方法。而pull解析器并没有强制要求提供触发的方法。因为它触发的事件并不是一个方法,而是一个数字。至于触发的事件要不要处理,由程序员自己决定。
示例:
1. PullParserHandler
package com.xml.demo.pull;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import org.xmlpull.v1.XmlPullParser;
import android.util.Xml;
import com.xml.demo.Person;
public class PullParserHandler {
private static final String TAG = "PullParserHandler";
public static List<Person> getPersons(InputStream inStream) throws Exception {
Person person = null;
List<Person> persons = null;
XmlPullParser pullParser = Xml.newPullParser();
pullParser.setInput(inStream, "UTF-8");
int event = pullParser.getEventType();// 触发第一个事件
while (event != XmlPullParser.END_DOCUMENT) {
switch (event) {
case XmlPullParser.START_DOCUMENT:
persons = new ArrayList<Person>();
break;
case XmlPullParser.START_TAG:
if ("person".equals(pullParser.getName())) {
int id = Integer.valueOf(pullParser.getAttributeValue(0));
person = new Person();
person.setId(id);
}
if (person != null) {
if ("name".equals(pullParser.getName())) {
person.setName(pullParser.nextText());
}
if ("age".equals(pullParser.getName())) {
person.setAge(new Short(pullParser.nextText()));
}
}
break;
case XmlPullParser.END_TAG:
if ("person".equals(pullParser.getName())) {
persons.add(person);
person = null;
}
break;
}
event = pullParser.next();
}
return persons;
}
}
说明:
a. “int event = pullParser.getEventType()”是pull解析器的第一个事件,这个方法的返回值是int类型,这就是前面提到的pull解析器返回的是一个数字,类似于一个信号。那么这些信号都代表什么意思呢?Pull解析器已经定义了这五个常亮,而且对于事件,仅仅只有这5个,如下:
-
START_DOCUMENT(开始解析)
-
START_TAG(开始元素)
-
TEXT(解析文本)
-
END_TAG(结束元素)
-
END_DOCUMENT(结束解析)
b. pullParser.getEventType()触发了第一个事件,根据XML的语法,也就是从它开始了解析文档。那么,怎么样触发下一个事件呢?要通过parser中最重要的方法:
pullParser.next()
注意:该方法是有返回值的,在Pull触发下一个事件的同时,也获得该事件的“信号”。通过获得的信号进行switch操作。
c. pullParser.getAttributeValue获得相应属性的值。它有两种形式,可以通过属性的索引,也可以通过(命名空间,属性名)进行索引。
2. MainActivity
package com.xml.demo;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import android.app.Activity;
import android.content.res.AssetManager;
import android.os.Bundle;
import android.util.Log;
import com.xml.demo.pull.PullParserHandler;
public class MainActivity extends Activity {
String TAG = "ZZMainActivity";
private AssetManager mAssetManager;
private InputStream mInputStream;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mAssetManager = getApplicationContext().getAssets();
try {
mInputStream = mAssetManager.open("test.xml");
} catch (IOException e) {
e.printStackTrace();
}
testPullParser();
}
private void testPullParser() {
List<Person> persons;
try {
persons = PullParserHandler.getPersons(mInputStream);
if (persons != null) {
for (Person person : persons) {
Log.i(TAG, person.toString());
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
四、使用PULL生成XML
SAX不支持xml文件的修改、生成,下面介绍下如何使用Pull来生成一个XML
XML中的标签时成对出现的,又开始,必有结束,所以在写入一个startTag()时,笔者习惯紧跟着写入与之相对应的endTag(),这样不至于在复杂的生成结构时,弄错了XML生成结构
示例1:
1. PullParserHandler.java
package com.xml.demo.pull;
import java.io.OutputStream;
import java.util.List;
import org.xmlpull.v1.XmlSerializer;
import android.util.Xml;
import com.xml.demo.Person;
public class PullParserHandler {
private static final String TAG = "PullParserHandler";
public static void save(List<Person> persons, OutputStream outStream) throws Exception {
XmlSerializer serializer = Xml.newSerializer();
serializer.setOutput(outStream, "UTF-8");
serializer.startDocument("UTF-8", true);
serializer.startTag(null, "persons");
for (Person person : persons) {
serializer.startTag(null, "person");
serializer.attribute(null, "id", person.getId().toString());
serializer.startTag(null, "name");
serializer.text(person.getName());
serializer.endTag(null, "name");
serializer.startTag(null, "age");
serializer.text(person.getAge().toString());
serializer.endTag(null, "age");
serializer.endTag(null, "person");
}
serializer.endTag(null, "persons");
serializer.endDocument();
outStream.flush();
outStream.close();
}
}
2. MainActivity.java
package com.xml.demo;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.content.res.AssetManager;
import android.os.Bundle;
import com.xml.demo.pull.PullParserHandler;
public class MainActivity extends Activity {
String TAG = "ZZMainActivity";
private AssetManager mAssetManager;
private InputStream mInputStream;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
testSaveXml();
}
private void testSaveXml() {
File file = new File(this.getFilesDir(), "toXmlFile.xml");
FileOutputStream outStream;
try {
outStream = new FileOutputStream(file);
List<Person> persons = new ArrayList<Person>();
persons.add(new Person(90, "zhangsan", (short) 13));
persons.add(new Person(35, "wangwu", (short) 23));
persons.add(new Person(78, "zhaoliu", (short) 33));
PullParserHandler.save(persons, outStream);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
上述生成的xml文件保存在 /data/data/com.xml.demo/files目录下:
<?xml version='1.0' encoding='UTF-8' standalone='yes' ?><persons><person id="90"><name>zhangsan</name><age>13</age></person><person id="35"><name>wangwu</name><age>23</age></person><person id="78"><name>zhaoliu</name><age>33</age></person></persons>
示例2:
使用Android提供的工具类:FastXmlSerializer.java 和 XmlUtils.java 来生成xml文件,生成的xml文件是格式化后的,比较容易阅读,推荐使用
1. 工具类:FastXmlSerializer.java
package com.xml.demo.utils;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CoderResult;
import java.nio.charset.IllegalCharsetNameException;
import java.nio.charset.UnsupportedCharsetException;
import org.xmlpull.v1.XmlSerializer;
// copy from frameworks/base/core/java/com/android/internal/util/FastXmlSerializer.java 1.6
/**
* This is a quick and dirty implementation of XmlSerializer that isn't horribly
* painfully slow like the normal one. It only does what is needed for the
* specific XML files being written with it.
*/
public class FastXmlSerializer implements XmlSerializer {
private static final String ESCAPE_TABLE[] = new String[] { null, null, null, null, null, null, null, null, // 0-7
null, null, null, null, null, null, null, null, // 8-15
null, null, null, null, null, null, null, null, // 16-23
null, null, null, null, null, null, null, null, // 24-31
null, null, """, null, null, null, "&", null, // 32-39
null, null, null, null, null, null, null, null, // 40-47
null, null, null, null, null, null, null, null, // 48-55
null, null, null, null, "<", null, ">", null, // 56-63
};
private static final int BUFFER_LEN = 8192;
private final char[] mText = new char[BUFFER_LEN];
private int mPos;
private Writer mWriter;
private OutputStream mOutputStream;
private CharsetEncoder mCharset;
private ByteBuffer mBytes = ByteBuffer.allocate(BUFFER_LEN);
private boolean mInTag;
private void append(char c) throws IOException {
int pos = mPos;
if (pos >= (BUFFER_LEN - 1)) {
flush();
pos = mPos;
}
mText[pos] = c;
mPos = pos + 1;
}
private void append(String str, int i, final int length) throws IOException {
if (length > BUFFER_LEN) {
final int end = i + length;
while (i < end) {
int next = i + BUFFER_LEN;
append(str, i, next < end ? BUFFER_LEN : (end - i));
i = next;
}
return;
}
int pos = mPos;
if ((pos + length) > BUFFER_LEN) {
flush();
pos = mPos;
}
str.getChars(i, i + length, mText, pos);
mPos = pos + length;
}
private void append(char[] buf, int i, final int length) throws IOException {
if (length > BUFFER_LEN) {
final int end = i + length;
while (i < end) {
int next = i + BUFFER_LEN;
append(buf, i, next < end ? BUFFER_LEN : (end - i));
i = next;
}
return;
}
int pos = mPos;
if ((pos + length) > BUFFER_LEN) {
flush();
pos = mPos;
}
System.arraycopy(buf, i, mText, pos, length);
mPos = pos + length;
}
private void append(String str) throws IOException {
append(str, 0, str.length());
}
private void escapeAndAppendString(final String string) throws IOException {
final int N = string.length();
final char NE = (char) ESCAPE_TABLE.length;
final String[] escapes = ESCAPE_TABLE;
int lastPos = 0;
int pos;
for (pos = 0; pos < N; pos++) {
char c = string.charAt(pos);
if (c >= NE)
continue;
String escape = escapes[c];
if (escape == null)
continue;
if (lastPos < pos)
append(string, lastPos, pos - lastPos);
lastPos = pos + 1;
append(escape);
}
if (lastPos < pos)
append(string, lastPos, pos - lastPos);
}
private void escapeAndAppendString(char[] buf, int start, int len) throws IOException {
final char NE = (char) ESCAPE_TABLE.length;
final String[] escapes = ESCAPE_TABLE;
int end = start + len;
int lastPos = start;
int pos;
for (pos = start; pos < end; pos++) {
char c = buf[pos];
if (c >= NE)
continue;
String escape = escapes[c];
if (escape == null)
continue;
if (lastPos < pos)
append(buf, lastPos, pos - lastPos);
lastPos = pos + 1;
append(escape);
}
if (lastPos < pos)
append(buf, lastPos, pos - lastPos);
}
public XmlSerializer attribute(String namespace, String name, String value) throws IOException, IllegalArgumentException, IllegalStateException {
append(' ');
if (namespace != null) {
append(namespace);
append(':');
}
append(name);
append("=\"");
escapeAndAppendString(value);
append('"');
return this;
}
public void cdsect(String text) throws IOException, IllegalArgumentException, IllegalStateException {
throw new UnsupportedOperationException();
}
public void comment(String text) throws IOException, IllegalArgumentException, IllegalStateException {
throw new UnsupportedOperationException();
}
public void docdecl(String text) throws IOException, IllegalArgumentException, IllegalStateException {
throw new UnsupportedOperationException();
}
public void endDocument() throws IOException, IllegalArgumentException, IllegalStateException {
flush();
}
public XmlSerializer endTag(String namespace, String name) throws IOException, IllegalArgumentException, IllegalStateException {
if (mInTag) {
append(" />\n");
} else {
append("</");
if (namespace != null) {
append(namespace);
append(':');
}
append(name);
append(">\n");
}
mInTag = false;
return this;
}
public void entityRef(String text) throws IOException, IllegalArgumentException, IllegalStateException {
throw new UnsupportedOperationException();
}
private void flushBytes() throws IOException {
int position;
if ((position = mBytes.position()) > 0) {
mBytes.flip();
mOutputStream.write(mBytes.array(), 0, position);
mBytes.clear();
}
}
public void flush() throws IOException {
// Log.i("PackageManager", "flush mPos=" + mPos);
if (mPos > 0) {
if (mOutputStream != null) {
CharBuffer charBuffer = CharBuffer.wrap(mText, 0, mPos);
CoderResult result = mCharset.encode(charBuffer, mBytes, true);
while (true) {
if (result.isError()) {
throw new IOException(result.toString());
} else if (result.isOverflow()) {
flushBytes();
result = mCharset.encode(charBuffer, mBytes, true);
continue;
}
break;
}
flushBytes();
mOutputStream.flush();
} else {
mWriter.write(mText, 0, mPos);
mWriter.flush();
}
mPos = 0;
}
}
public int getDepth() {
throw new UnsupportedOperationException();
}
public boolean getFeature(String name) {
throw new UnsupportedOperationException();
}
public String getName() {
throw new UnsupportedOperationException();
}
public String getNamespace() {
throw new UnsupportedOperationException();
}
public String getPrefix(String namespace, boolean generatePrefix) throws IllegalArgumentException {
throw new UnsupportedOperationException();
}
public Object getProperty(String name) {
throw new UnsupportedOperationException();
}
public void ignorableWhitespace(String text) throws IOException, IllegalArgumentException, IllegalStateException {
throw new UnsupportedOperationException();
}
public void processingInstruction(String text) throws IOException, IllegalArgumentException, IllegalStateException {
throw new UnsupportedOperationException();
}
public void setFeature(String name, boolean state) throws IllegalArgumentException, IllegalStateException {
if (name.equals("http://xmlpull.org/v1/doc/features.html#indent-output")) {
return;
}
throw new UnsupportedOperationException();
}
public void setOutput(OutputStream os, String encoding) throws IOException, IllegalArgumentException, IllegalStateException {
if (os == null)
throw new IllegalArgumentException();
if (true) {
try {
mCharset = Charset.forName(encoding).newEncoder();
} catch (IllegalCharsetNameException e) {
throw (UnsupportedEncodingException) (new UnsupportedEncodingException(encoding).initCause(e));
} catch (UnsupportedCharsetException e) {
throw (UnsupportedEncodingException) (new UnsupportedEncodingException(encoding).initCause(e));
}
mOutputStream = os;
} else {
setOutput(encoding == null ? new OutputStreamWriter(os) : new OutputStreamWriter(os, encoding));
}
}
public void setOutput(Writer writer) throws IOException, IllegalArgumentException, IllegalStateException {
mWriter = writer;
}
public void setPrefix(String prefix, String namespace) throws IOException, IllegalArgumentException, IllegalStateException {
throw new UnsupportedOperationException();
}
public void setProperty(String name, Object value) throws IllegalArgumentException, IllegalStateException {
throw new UnsupportedOperationException();
}
public void startDocument(String encoding, Boolean standalone) throws IOException, IllegalArgumentException, IllegalStateException {
append("<?xml version='1.0' encoding='utf-8' standalone='" + (standalone ? "yes" : "no") + "' ?>\n");
}
public XmlSerializer startTag(String namespace, String name) throws IOException, IllegalArgumentException, IllegalStateException {
if (mInTag) {
append(">\n");
}
append('<');
if (namespace != null) {
append(namespace);
append(':');
}
append(name);
mInTag = true;
return this;
}
public XmlSerializer text(char[] buf, int start, int len) throws IOException, IllegalArgumentException, IllegalStateException {
if (mInTag) {
append(">");
mInTag = false;
}
escapeAndAppendString(buf, start, len);
return this;
}
public XmlSerializer text(String text) throws IOException, IllegalArgumentException, IllegalStateException {
if (mInTag) {
append(">");
mInTag = false;
}
escapeAndAppendString(text);
return this;
}
}
2. 工具类:XmlUtils.java
package com.xml.demo.utils;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
import android.util.Xml;
// copy from frameworks/base/core/java/com/android/internal/util/XmlUtils.java 1.6
public class XmlUtils {
public static void skipCurrentTag(XmlPullParser parser) throws XmlPullParserException, IOException {
int outerDepth = parser.getDepth();
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
}
}
public static final int convertValueToList(CharSequence value, String[] options, int defaultValue) {
if (null != value) {
for (int i = 0; i < options.length; i++) {
if (value.equals(options[i]))
return i;
}
}
return defaultValue;
}
public static final boolean convertValueToBoolean(CharSequence value, boolean defaultValue) {
boolean result = false;
if (null == value)
return defaultValue;
if (value.equals("1") || value.equals("true") || value.equals("TRUE"))
result = true;
return result;
}
public static final int convertValueToInt(CharSequence charSeq, int defaultValue) {
if (null == charSeq)
return defaultValue;
String nm = charSeq.toString();
// XXX This code is copied from Integer.decode() so we don't
// have to instantiate an Integer!
int value;
int sign = 1;
int index = 0;
int len = nm.length();
int base = 10;
if ('-' == nm.charAt(0)) {
sign = -1;
index++;
}
if ('0' == nm.charAt(index)) {
// Quick check for a zero by itself
if (index == (len - 1))
return 0;
char c = nm.charAt(index + 1);
if ('x' == c || 'X' == c) {
index += 2;
base = 16;
} else {
index++;
base = 8;
}
} else if ('#' == nm.charAt(index)) {
index++;
base = 16;
}
return Integer.parseInt(nm.substring(index), base) * sign;
}
public static final int convertValueToUnsignedInt(String value, int defaultValue) {
if (null == value)
return defaultValue;
return parseUnsignedIntAttribute(value);
}
public static final int parseUnsignedIntAttribute(CharSequence charSeq) {
String value = charSeq.toString();
long bits;
int index = 0;
int len = value.length();
int base = 10;
if ('0' == value.charAt(index)) {
// Quick check for zero by itself
if (index == (len - 1))
return 0;
char c = value.charAt(index + 1);
if ('x' == c || 'X' == c) { // check for hex
index += 2;
base = 16;
} else { // check for octal
index++;
base = 8;
}
} else if ('#' == value.charAt(index)) {
index++;
base = 16;
}
return (int) Long.parseLong(value.substring(index), base);
}
/**
* Flatten a Map into an output stream as XML. The map can later be read
* back with readMapXml().
*
* @param val
* The map to be flattened.
* @param out
* Where to write the XML data.
*
* @see #writeMapXml(Map, String, XmlSerializer)
* @see #writeListXml
* @see #writeValueXml
* @see #readMapXml
*/
public static final void writeMapXml(Map val, OutputStream out) throws XmlPullParserException, java.io.IOException {
XmlSerializer serializer = new FastXmlSerializer();
serializer.setOutput(out, "utf-8");
serializer.startDocument(null, true);
serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
writeMapXml(val, null, serializer);
serializer.endDocument();
}
/**
* Flatten a List into an output stream as XML. The list can later be read
* back with readListXml().
*
* @param val
* The list to be flattened.
* @param out
* Where to write the XML data.
*
* @see #writeListXml(List, String, XmlSerializer)
* @see #writeMapXml
* @see #writeValueXml
* @see #readListXml
*/
public static final void writeListXml(List val, OutputStream out) throws XmlPullParserException, java.io.IOException {
XmlSerializer serializer = Xml.newSerializer();
serializer.setOutput(out, "utf-8");
serializer.startDocument(null, true);
serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
writeListXml(val, null, serializer);
serializer.endDocument();
}
/**
* Flatten a Map into an XmlSerializer. The map can later be read back with
* readThisMapXml().
*
* @param val
* The map to be flattened.
* @param name
* Name attribute to include with this list's tag, or null for
* none.
* @param out
* XmlSerializer to write the map into.
*
* @see #writeMapXml(Map, OutputStream)
* @see #writeListXml
* @see #writeValueXml
* @see #readMapXml
*/
public static final void writeMapXml(Map val, String name, XmlSerializer out) throws XmlPullParserException, java.io.IOException {
if (val == null) {
out.startTag(null, "null");
out.endTag(null, "null");
return;
}
Set s = val.entrySet();
Iterator i = s.iterator();
out.startTag(null, "map");
if (name != null) {
out.attribute(null, "name", name);
}
while (i.hasNext()) {
Map.Entry e = (Map.Entry) i.next();
writeValueXml(e.getValue(), (String) e.getKey(), out);
}
out.endTag(null, "map");
}
/**
* Flatten a List into an XmlSerializer. The list can later be read back
* with readThisListXml().
*
* @param val
* The list to be flattened.
* @param name
* Name attribute to include with this list's tag, or null for
* none.
* @param out
* XmlSerializer to write the list into.
*
* @see #writeListXml(List, OutputStream)
* @see #writeMapXml
* @see #writeValueXml
* @see #readListXml
*/
public static final void writeListXml(List val, String name, XmlSerializer out) throws XmlPullParserException, java.io.IOException {
if (val == null) {
out.startTag(null, "null");
out.endTag(null, "null");
return;
}
out.startTag(null, "list");
if (name != null) {
out.attribute(null, "name", name);
}
int N = val.size();
int i = 0;
while (i < N) {
writeValueXml(val.get(i), null, out);
i++;
}
out.endTag(null, "list");
}
/**
* Flatten a byte[] into an XmlSerializer. The list can later be read back
* with readThisByteArrayXml().
*
* @param val
* The byte array to be flattened.
* @param name
* Name attribute to include with this array's tag, or null for
* none.
* @param out
* XmlSerializer to write the array into.
*
* @see #writeMapXml
* @see #writeValueXml
*/
public static final void writeByteArrayXml(byte[] val, String name, XmlSerializer out) throws XmlPullParserException, java.io.IOException {
if (val == null) {
out.startTag(null, "null");
out.endTag(null, "null");
return;
}
out.startTag(null, "byte-array");
if (name != null) {
out.attribute(null, "name", name);
}
final int N = val.length;
out.attribute(null, "num", Integer.toString(N));
StringBuilder sb = new StringBuilder(val.length * 2);
for (int i = 0; i < N; i++) {
int b = val[i];
int h = b >> 4;
sb.append(h >= 10 ? ('a' + h - 10) : ('0' + h));
h = b & 0xff;
sb.append(h >= 10 ? ('a' + h - 10) : ('0' + h));
}
out.text(sb.toString());
out.endTag(null, "byte-array");
}
/**
* Flatten an int[] into an XmlSerializer. The list can later be read back
* with readThisIntArrayXml().
*
* @param val
* The int array to be flattened.
* @param name
* Name attribute to include with this array's tag, or null for
* none.
* @param out
* XmlSerializer to write the array into.
*
* @see #writeMapXml
* @see #writeValueXml
* @see #readThisIntArrayXml
*/
public static final void writeIntArrayXml(int[] val, String name, XmlSerializer out) throws XmlPullParserException, java.io.IOException {
if (val == null) {
out.startTag(null, "null");
out.endTag(null, "null");
return;
}
out.startTag(null, "int-array");
if (name != null) {
out.attribute(null, "name", name);
}
final int N = val.length;
out.attribute(null, "num", Integer.toString(N));
for (int i = 0; i < N; i++) {
out.startTag(null, "item");
out.attribute(null, "value", Integer.toString(val[i]));
out.endTag(null, "item");
}
out.endTag(null, "int-array");
}
/**
* Flatten an object's value into an XmlSerializer. The value can later be
* read back with readThisValueXml().
*
* Currently supported value types are: null, String, Integer, Long, Float,
* Double Boolean, Map, List.
*
* @param v
* The object to be flattened.
* @param name
* Name attribute to include with this value's tag, or null for
* none.
* @param out
* XmlSerializer to write the object into.
*
* @see #writeMapXml
* @see #writeListXml
* @see #readValueXml
*/
public static final void writeValueXml(Object v, String name, XmlSerializer out) throws XmlPullParserException, java.io.IOException {
String typeStr;
if (v == null) {
out.startTag(null, "null");
if (name != null) {
out.attribute(null, "name", name);
}
out.endTag(null, "null");
return;
} else if (v instanceof String) {
out.startTag(null, "string");
if (name != null) {
out.attribute(null, "name", name);
}
out.text(v.toString());
out.endTag(null, "string");
return;
} else if (v instanceof Integer) {
typeStr = "int";
} else if (v instanceof Long) {
typeStr = "long";
} else if (v instanceof Float) {
typeStr = "float";
} else if (v instanceof Double) {
typeStr = "double";
} else if (v instanceof Boolean) {
typeStr = "boolean";
} else if (v instanceof byte[]) {
writeByteArrayXml((byte[]) v, name, out);
return;
} else if (v instanceof int[]) {
writeIntArrayXml((int[]) v, name, out);
return;
} else if (v instanceof Map) {
writeMapXml((Map) v, name, out);
return;
} else if (v instanceof List) {
writeListXml((List) v, name, out);
return;
} else if (v instanceof CharSequence) {
// XXX This is to allow us to at least write something if
// we encounter styled text... but it means we will drop all
// of the styling information. :(
out.startTag(null, "string");
if (name != null) {
out.attribute(null, "name", name);
}
out.text(v.toString());
out.endTag(null, "string");
return;
} else {
throw new RuntimeException("writeValueXml: unable to write value " + v);
}
out.startTag(null, typeStr);
if (name != null) {
out.attribute(null, "name", name);
}
out.attribute(null, "value", v.toString());
out.endTag(null, typeStr);
}
/**
* Read a HashMap from an InputStream containing XML. The stream can
* previously have been written by writeMapXml().
*
* @param in
* The InputStream from which to read.
*
* @return HashMap The resulting map.
*
* @see #readListXml
* @see #readValueXml
* @see #readThisMapXml #see #writeMapXml
*/
public static final HashMap readMapXml(InputStream in) throws XmlPullParserException, java.io.IOException {
XmlPullParser parser = Xml.newPullParser();
parser.setInput(in, null);
return (HashMap) readValueXml(parser, new String[1]);
}
/**
* Read an ArrayList from an InputStream containing XML. The stream can
* previously have been written by writeListXml().
*
* @param in
* The InputStream from which to read.
*
* @return HashMap The resulting list.
*
* @see #readMapXml
* @see #readValueXml
* @see #readThisListXml
* @see #writeListXml
*/
public static final ArrayList readListXml(InputStream in) throws XmlPullParserException, java.io.IOException {
XmlPullParser parser = Xml.newPullParser();
parser.setInput(in, null);
return (ArrayList) readValueXml(parser, new String[1]);
}
/**
* Read a HashMap object from an XmlPullParser. The XML data could
* previously have been generated by writeMapXml(). The XmlPullParser must
* be positioned <em>after</em> the tag that begins the map.
*
* @param parser
* The XmlPullParser from which to read the map data.
* @param endTag
* Name of the tag that will end the map, usually "map".
* @param name
* An array of one string, used to return the name attribute of
* the map's tag.
*
* @return HashMap The newly generated map.
*
* @see #readMapXml
*/
public static final HashMap readThisMapXml(XmlPullParser parser, String endTag, String[] name) throws XmlPullParserException, java.io.IOException {
HashMap map = new HashMap();
int eventType = parser.getEventType();
do {
if (eventType == parser.START_TAG) {
Object val = readThisValueXml(parser, name);
if (name[0] != null) {
// System.out.println("Adding to map: " + name + " -> " +
// val);
map.put(name[0], val);
} else {
throw new XmlPullParserException("Map value without name attribute: " + parser.getName());
}
} else if (eventType == parser.END_TAG) {
if (parser.getName().equals(endTag)) {
return map;
}
throw new XmlPullParserException("Expected " + endTag + " end tag at: " + parser.getName());
}
eventType = parser.next();
} while (eventType != parser.END_DOCUMENT);
throw new XmlPullParserException("Document ended before " + endTag + " end tag");
}
/**
* Read an ArrayList object from an XmlPullParser. The XML data could
* previously have been generated by writeListXml(). The XmlPullParser must
* be positioned <em>after</em> the tag that begins the list.
*
* @param parser
* The XmlPullParser from which to read the list data.
* @param endTag
* Name of the tag that will end the list, usually "list".
* @param name
* An array of one string, used to return the name attribute of
* the list's tag.
*
* @return HashMap The newly generated list.
*
* @see #readListXml
*/
public static final ArrayList readThisListXml(XmlPullParser parser, String endTag, String[] name) throws XmlPullParserException, java.io.IOException {
ArrayList list = new ArrayList();
int eventType = parser.getEventType();
do {
if (eventType == parser.START_TAG) {
Object val = readThisValueXml(parser, name);
list.add(val);
// System.out.println("Adding to list: " + val);
} else if (eventType == parser.END_TAG) {
if (parser.getName().equals(endTag)) {
return list;
}
throw new XmlPullParserException("Expected " + endTag + " end tag at: " + parser.getName());
}
eventType = parser.next();
} while (eventType != parser.END_DOCUMENT);
throw new XmlPullParserException("Document ended before " + endTag + " end tag");
}
/**
* Read an int[] object from an XmlPullParser. The XML data could previously
* have been generated by writeIntArrayXml(). The XmlPullParser must be
* positioned <em>after</em> the tag that begins the list.
*
* @param parser
* The XmlPullParser from which to read the list data.
* @param endTag
* Name of the tag that will end the list, usually "list".
* @param name
* An array of one string, used to return the name attribute of
* the list's tag.
*
* @return Returns a newly generated int[].
*
* @see #readListXml
*/
public static final int[] readThisIntArrayXml(XmlPullParser parser, String endTag, String[] name) throws XmlPullParserException, java.io.IOException {
int num;
try {
num = Integer.parseInt(parser.getAttributeValue(null, "num"));
} catch (NullPointerException e) {
throw new XmlPullParserException("Need num attribute in byte-array");
} catch (NumberFormatException e) {
throw new XmlPullParserException("Not a number in num attribute in byte-array");
}
int[] array = new int[num];
int i = 0;
int eventType = parser.getEventType();
do {
if (eventType == parser.START_TAG) {
if (parser.getName().equals("item")) {
try {
array[i] = Integer.parseInt(parser.getAttributeValue(null, "value"));
} catch (NullPointerException e) {
throw new XmlPullParserException("Need value attribute in item");
} catch (NumberFormatException e) {
throw new XmlPullParserException("Not a number in value attribute in item");
}
} else {
throw new XmlPullParserException("Expected item tag at: " + parser.getName());
}
} else if (eventType == parser.END_TAG) {
if (parser.getName().equals(endTag)) {
return array;
} else if (parser.getName().equals("item")) {
i++;
} else {
throw new XmlPullParserException("Expected " + endTag + " end tag at: " + parser.getName());
}
}
eventType = parser.next();
} while (eventType != parser.END_DOCUMENT);
throw new XmlPullParserException("Document ended before " + endTag + " end tag");
}
/**
* Read a flattened object from an XmlPullParser. The XML data could
* previously have been written with writeMapXml(), writeListXml(), or
* writeValueXml(). The XmlPullParser must be positioned <em>at</em> the tag
* that defines the value.
*
* @param parser
* The XmlPullParser from which to read the object.
* @param name
* An array of one string, used to return the name attribute of
* the value's tag.
*
* @return Object The newly generated value object.
*
* @see #readMapXml
* @see #readListXml
* @see #writeValueXml
*/
public static final Object readValueXml(XmlPullParser parser, String[] name) throws XmlPullParserException, java.io.IOException {
int eventType = parser.getEventType();
do {
if (eventType == parser.START_TAG) {
return readThisValueXml(parser, name);
} else if (eventType == parser.END_TAG) {
throw new XmlPullParserException("Unexpected end tag at: " + parser.getName());
} else if (eventType == parser.TEXT) {
throw new XmlPullParserException("Unexpected text: " + parser.getText());
}
eventType = parser.next();
} while (eventType != parser.END_DOCUMENT);
throw new XmlPullParserException("Unexpected end of document");
}
private static final Object readThisValueXml(XmlPullParser parser, String[] name) throws XmlPullParserException, java.io.IOException {
final String valueName = parser.getAttributeValue(null, "name");
final String tagName = parser.getName();
// System.out.println("Reading this value tag: " + tagName + ", name=" +
// valueName);
Object res;
if (tagName.equals("null")) {
res = null;
} else if (tagName.equals("string")) {
String value = "";
int eventType;
while ((eventType = parser.next()) != parser.END_DOCUMENT) {
if (eventType == parser.END_TAG) {
if (parser.getName().equals("string")) {
name[0] = valueName;
// System.out.println("Returning value for " + valueName
// + ": " + value);
return value;
}
throw new XmlPullParserException("Unexpected end tag in <string>: " + parser.getName());
} else if (eventType == parser.TEXT) {
value += parser.getText();
} else if (eventType == parser.START_TAG) {
throw new XmlPullParserException("Unexpected start tag in <string>: " + parser.getName());
}
}
throw new XmlPullParserException("Unexpected end of document in <string>");
} else if (tagName.equals("int")) {
res = Integer.parseInt(parser.getAttributeValue(null, "value"));
} else if (tagName.equals("long")) {
res = Long.valueOf(parser.getAttributeValue(null, "value"));
} else if (tagName.equals("float")) {
res = new Float(parser.getAttributeValue(null, "value"));
} else if (tagName.equals("double")) {
res = new Double(parser.getAttributeValue(null, "value"));
} else if (tagName.equals("boolean")) {
res = Boolean.valueOf(parser.getAttributeValue(null, "value"));
} else if (tagName.equals("int-array")) {
parser.next();
res = readThisIntArrayXml(parser, "int-array", name);
name[0] = valueName;
// System.out.println("Returning value for " + valueName + ": " +
// res);
return res;
} else if (tagName.equals("map")) {
parser.next();
res = readThisMapXml(parser, "map", name);
name[0] = valueName;
// System.out.println("Returning value for " + valueName + ": " +
// res);
return res;
} else if (tagName.equals("list")) {
parser.next();
res = readThisListXml(parser, "list", name);
name[0] = valueName;
// System.out.println("Returning value for " + valueName + ": " +
// res);
return res;
} else {
throw new XmlPullParserException("Unknown tag: " + tagName);
}
// Skip through to end tag.
int eventType;
while ((eventType = parser.next()) != parser.END_DOCUMENT) {
if (eventType == parser.END_TAG) {
if (parser.getName().equals(tagName)) {
name[0] = valueName;
// System.out.println("Returning value for " + valueName +
// ": " + res);
return res;
}
throw new XmlPullParserException("Unexpected end tag in <" + tagName + ">: " + parser.getName());
} else if (eventType == parser.TEXT) {
throw new XmlPullParserException("Unexpected text in <" + tagName + ">: " + parser.getName());
} else if (eventType == parser.START_TAG) {
throw new XmlPullParserException("Unexpected start tag in <" + tagName + ">: " + parser.getName());
}
}
throw new XmlPullParserException("Unexpected end of document in <" + tagName + ">");
}
public static final void beginDocument(XmlPullParser parser, String firstElementName) throws XmlPullParserException, IOException {
int type;
while ((type = parser.next()) != parser.START_TAG && type != parser.END_DOCUMENT) {
;
}
if (type != parser.START_TAG) {
throw new XmlPullParserException("No start tag found");
}
if (!parser.getName().equals(firstElementName)) {
throw new XmlPullParserException("Unexpected start tag: found " + parser.getName() + ", expected " + firstElementName);
}
}
public static final void nextElement(XmlPullParser parser) throws XmlPullParserException, IOException {
int type;
while ((type = parser.next()) != parser.START_TAG && type != parser.END_DOCUMENT) {
;
}
}
}
3. MainActivity.java
package com.xml.demo;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import org.xmlpull.v1.XmlSerializer;
import android.app.Activity;
import android.content.res.AssetManager;
import android.os.Bundle;
import android.util.Log;
import com.xml.demo.utils.FastXmlSerializer;
public class MainActivity extends Activity {
String TAG = "ZZMainActivity";
private AssetManager mAssetManager;
private InputStream mInputStream;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mAssetManager = getApplicationContext().getAssets();
try {
mInputStream = mAssetManager.open("test.xml");
} catch (IOException e) {
e.printStackTrace();
}
testSaveXmlWithUtils();
}
private void testSaveXmlWithUtils() { // 生成xml文件
List<Person> persons = new ArrayList<Person>();
persons.add(new Person(80, "zhangsan", (short) 13));
persons.add(new Person(30, "wangwu", (short) 23));
persons.add(new Person(70, "zhaoliu", (short) 33));
try {
File file = new File(this.getFilesDir(), "toXmlFile.xml");
FileOutputStream str = new FileOutputStream(file);
XmlSerializer serializer = new FastXmlSerializer();
serializer.setOutput(str, "utf-8");
serializer.startDocument(null, true);
serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
serializer.startTag(null, "persons");
for (Person person : persons) {
serializer.startTag(null, "person");
serializer.attribute(null, "id", person.getId().toString());
serializer.startTag(null, "name");
serializer.text(person.getName());
serializer.endTag(null, "name");
serializer.startTag(null, "age");
serializer.text(person.getAge().toString());
serializer.endTag(null, "age");
serializer.endTag(null, "person");
}
serializer.endTag(null, "persons");
serializer.endDocument();
str.flush();
str.close();
} catch (IOException e) {
Log.w(TAG, "IOException:", e);
}
}
}
/data/data/com.xml.demo/files/toXmlFile.xml 文件:
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<persons>
<person id="80">
<name>zhangsan</name>
<age>13</age>
</person>
<person id="30">
<name>wangwu</name>
<age>23</age>
</person>
<person id="70">
<name>zhaoliu</name>
<age>33</age>
</person>
</persons>
可以看到,通过上述工具类生成的xml文件,没有在同一行显示,比较格式化,看起来比较阅读。此时读取xml文件内容,可以参考 PullParserHandler类的getPersons()方法实现。
另外代码片段示例:
通过上述 FastXmlSerializer 生成xml文件,然后通过 Xml.newPullParser 读取xml文件
private void writePreloadApkList(List<PreloadPackage> preloadApkList) {
if (preloadApkList != null && preloadApkList.size() == 0) {
Slog.d(TAG, "preload list size is 0");
return;
}
FileOutputStream str = null;
try {
// TODO: delete it ?
if (mPreloadListSaveFilePath != null && mPreloadListSaveFilePath.exists()) {
Slog.d(TAG, "writePreloadList delete file");
mPreloadListSaveFilePath.delete();
}
mPreloadListSaveFilePath = new File(mPreloadSaveFileDir.getPath() + mPreloadApkListFileName);
str = new FileOutputStream(mPreloadListSaveFilePath);
XmlSerializer serializer = new FastXmlSerializer();
serializer.setOutput(str, "utf-8");
serializer.startDocument(null, true);
serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
for (PreloadPackage preloadApp : preloadApkList) {
serializer.startTag(null, "PackageItem");
serializer.attribute(null, "packageName", preloadApp.packageName);
serializer.attribute(null, "codePath", preloadApp.codePath);
serializer.attribute(null, "originalCodePath", preloadApp.originalCodePath);
serializer.endTag(null, "PackageItem");
}
serializer.endDocument();
str.flush();
str.close();
} catch (IOException e) {
Slog.e(TAG, "IOException:", e);
} finally {
if (str != null) {
IoUtils.closeQuietly(str);
}
}
}
private List<PreloadPackage> readPreloadApkList() {
mPreloadListSaveFilePath = new File(mPreloadSaveFileDir.getPath() + mPreloadApkListFileName);
if (!mPreloadListSaveFilePath.exists()) {
Slog.e(TAG, "preload file not exist");
return new ArrayList<PreloadPackage>(); // Length is 0
}
FileInputStream str = null;
try {
str = new FileInputStream(mPreloadListSaveFilePath);
} catch (FileNotFoundException e) {
Slog.e(TAG, "read " + e);
}
List<PreloadPackage> preloadPackageList;
PreloadPackage preloadPackage;
try {
preloadPackageList = new ArrayList<PreloadPackage>();
XmlPullParser parser = Xml.newPullParser();
parser.setInput(str, null);
int type;
int outerDepth = parser.getDepth();
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
continue;
}
String rootItem = parser.getName();
String pkgName = parser.getAttributeValue(null, "packageName");
String codePath = parser.getAttributeValue(null, "codePath");
String originalCodePath = parser.getAttributeValue(null, "originalCodePath");
String versionCode = parser.getAttributeValue(null, "versionCode");
if (DBG)
Slog.d(TAG, "read preload " + rootItem + " packageName:" + pkgName + " codePath:" + codePath + " versionCode:" + versionCode);
if (!TextUtils.isEmpty(pkgName)) {
preloadPackage = new PreloadPackage();
preloadPackage.packageName = pkgName;
preloadPackage.codePath = codePath;
preloadPackage.originalCodePath = originalCodePath;
preloadPackageList.add(preloadPackage);
}
}
return preloadPackageList;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (XmlPullParserException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (str != null) {
IoUtils.closeQuietly(str);
}
}
return new ArrayList<PreloadPackage>(); // Length is 0
}
五、SAX、DOM、Pull的比较
1. 内存占用:
SAX、Pull 优于DOM
2. 编程方式
推荐 Pull
3.访问方式
SAX、Pull解析的方式是同步的,即解析器读到哪里,就对哪里进行处理。而DOM是已经将文件解析好后,供用户读取XML中感兴趣的内容。
个人总结:
推荐使用Android提供的FastXmlSerializer.java和XmlUtils.java来生成xml文件,读取xml文件按照Pull的方式读取即可。
本篇内容参考:Android 4.0 网络编程详解(王家林著)