Android SAX、DOM、Pull解析xml文件剖析与案例讲解

XML介绍
XML(Extensible Markup Language) 即可扩展标记语言,与HTML一样,都是SGML(Standard Generalized Markup Language,标准通用标记语言)。XML是跨平台的,依赖于内容的技术,是当前处理结构化文档信息的有利工具。扩展标记语言XML是一种简单的数据存储语言,使用一系列简单的标记描述数据,而这些标记可以用方便的方式建立,虽然XML占用的空间比二进制数据要占用更多的空间,但XML简单且易于使用。
 
由于XML扩展性强,致使它需要稳定的基础规则来支持扩展。XML语言规则:
  • 起始和结束的标签相匹配
  • 嵌套标签不能相互嵌套
  • 区分大小写
 
Android SAX、DOM、Pull解析xml文件剖析与案例讲解
Android SAX、DOM、Pull解析xml文件剖析与案例讲解
 Android SAX、DOM、Pull解析xml文件剖析与案例讲解
Android SAX、DOM、Pull解析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文档作为一个树形结构,这种树形街结构也被称为节点树
 
Android SAX、DOM、Pull解析xml文件剖析与案例讲解
Android SAX、DOM、Pull解析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个,如下:
 
  1. START_DOCUMENT(开始解析)
  2. START_TAG(开始元素)
  3. TEXT(解析文本)
  4. END_TAG(结束元素)
  5. 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, "&quot;", null, null, null, "&amp;", 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, "&lt;", null, "&gt;", 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()方法实现。
 
 
五、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 网络编程详解(王家林著)
 
上一篇:如何解决编译linux内核(解决声卡问题),遭遇fatal error: linux/limits.h: 没有那个文件或目录


下一篇:WCF系列教程之WCF服务宿主与WCF服务部署