在Android中,Xml有三种解析方式,对应也有三种创建方式,分别是Dom解析,Pull解析,Sax解析。

1.Dom解析

DOM是基于树形结构的的节点或信息片段的集合,允许开发人员使用DOM API遍历XML树、检索所需数据。分析该结构通常需要加载整个文档和构造树形结构,然后才可以检索和更新节点信息。Android完全支持DOM 解析。利用DOM中的对象,可以对XML文档进行读取、搜索、修改、添加和删除等操作。

DOM的工作原理:使用DOM对XML文件进行操作时,首先要解析文件,将文件分为独立的元素、属性和注释等,然后以节点树的形式在内存中对XML文件进行表示,就可以通过节点树访问文档的内容,并根据需要修改文档——这就是DOM的工作原理。

DOM实现时首先为XML文档的解析定义一组接口,解析器读入整个文档,然后构造一个驻留内存的树结构,这样代码就可以使用DOM接口来操作整个树结构。

由于DOM在内存中以树形结构存放,因此检索和更新效率会更高。但是对于特别大的文档,解析和加载整个文档将会很耗资源。 当然,如果XML文件的内容比较小,采用DOM是可行的。

常用的DoM接口和类:

Document:该接口定义分析并创建DOM文档的一系列方法,它是文档树的根,是操作DOM的基础。

Element:该接口继承Node接口,提供了获取、修改XML元素名字和属性的方法。

Node:该接口提供处理并获取节点和子节点值的方法。

NodeList:提供获得节点个数和当前节点的方法。这样就可以迭代地访问各个节点。

DOMParser:该类是Apache的Xerces中的DOM解析器类,可直接解析XML文件。
DocumentBuilderFactory:单例类,是一个工厂类;
DocumentBuilder: Document构建类

DomParseTool类

package factory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import bean.Book;

/**
 * Created by John on 2016/12/4.
 */

public class DomParseTool extends XMLParseFactory {

    List<Book> bookList;
    DocumentBuilderFactory factory;
    DocumentBuilder builder;


    public DomParseTool() {
        bookList = new ArrayList<Book>();
        factory = DocumentBuilderFactory.newInstance();
        try {
            builder = factory.newDocumentBuilder();
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        }
    }


    @Override
    public void readXML(InputStream mInputStream) {
        try {
            Document document = builder.parse(mInputStream);
            Element element = document.getDocumentElement();
            NodeList nodeList = element.getElementsByTagName(Book.BOOK);
            for (int i = 0; i < nodeList.getLength(); i++) {
                Element ele = (Element) nodeList.item(i);
                Book book = new Book();
                book.setId(Integer.valueOf(ele.getAttribute(Book.ID)));
                NodeList childNodeList = ele.getChildNodes();
                for (int j = 0; j < childNodeList.getLength(); j++) {
                    Node childNode = childNodeList.item(j);
                    if (childNode.getNodeType() == Node.ELEMENT_NODE) {
                        if (Book.NAME.equals(childNode.getNodeName())) {
                            book.setName(childNode.getFirstChild().getNodeValue());
                        } else if (Book.PRICE.equals(childNode.getNodeName())) {
                            book.setPrice(Float.valueOf(childNode.getFirstChild().getNodeValue()));
                        }
                    }
                }
                bookList.add(book);
            }

        } catch (SAXException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }


    }


    @Override
    public void writeXML(String filePath) {

    }

    @Override
    public void writeXML(String filePath,List<Book> mBooks) {
        String str = filePath;
        Document doc = builder.newDocument();
        Element rootele = doc.createElement(Book.BOOKS);
        doc.appendChild(rootele);
        for (int i = 0; i <  mBooks.size(); i++) {
            Book book =  mBooks.get(i);
            Element bookEle = doc.createElement(Book.BOOK);
            bookEle.setAttribute(Book.ID, String.valueOf(book.getId()));
            Element nameEle = doc.createElement(Book.NAME);
            nameEle.appendChild(doc.createTextNode(book.getName()));
            bookEle.appendChild(nameEle);
            Element priceEle = doc.createElement(Book.PRICE);
            priceEle.appendChild(doc.createTextNode(String.valueOf(book.getPrice())));
            bookEle.appendChild(priceEle);
            rootele.appendChild(bookEle);
        }

        TransformerFactory mTransformerf = TransformerFactory.newInstance();
        try {
            Transformer mTransformer = mTransformerf.newTransformer();
            DOMSource resource = new DOMSource(doc);
            mTransformer.setOutputProperty(OutputKeys.ENCODING, "utf-8");
            mTransformer.setOutputProperty(OutputKeys.INDENT, "no");
            try {
                FileOutputStream fileOs = new FileOutputStream(filePath);
                PrintWriter pw = new PrintWriter(fileOs);
                StreamResult sr = new StreamResult(pw);
                mTransformer.transform(resource,sr);
            } catch (Exception e) {
                e.printStackTrace();
            }
        } catch (TransformerConfigurationException e) {
            e.printStackTrace();
        }

    }

    @Override
    public void setBookList(List<Book> mBookList) {
        this.bookList = mBookList;

    }

    @Override
    public List<Book> getBookList() {
        return bookList;
    }
}

2.Pull解析

Android并未提供对Java StAX API的支持。但是,Android附带了一个pull解析器,其工作方式类似于StAX。它允许用户的应用程序代码从解析器中获取事件,这与SAX解析器自动将事件推入处理程序相反。

PULL解析器的运行方式和SAX类似,都是基于事件的模式。不同的是,在PULL解析过程中返回的是数字,且我们需要自己获取产生的事件然后做相应的操作,而不像SAX那样由处理器触发一种事件的方法,执行我们的代码。

读取到xml的声明返回 START_DOCUMENT;

读取到xml的结束返回 END_DOCUMENT ;

读取到xml的开始标签返回 START_TAG

读取到xml的结束标签返回 END_TAG

读取到xml的文本返回 TEXT

PULL解析器小巧轻便,解析速度快,简单易用,非常适合在Android移动设备中使用,Android系统内部在解析各种XML时也是用PULL解析器,Android官方推荐开发者们使用Pull解析技术。Pull解析技术是第三方开发的开源技术,它同样可以应用于JavaSE开发。

PULL 的工作原理:XML pull提供了开始元素和结束元素。当某个元素开始时,我们可以调用parser.nextText从XML文档中提取所有字符数据。当解释到一个文档结束时,自动生成EndDocument事件。

常用的XML pull的接口和类:

XmlPullParser:XML pull解析器是一个在XMLPULL VlAP1中提供了定义解析功能的接口。

XmlSerializer:它是一个接口,定义了XML信息集的序列。

XmlPullParserFactory:这个类用于在XMPULL V1 API中创建XML Pull解析器。

XmlPullParserException:抛出单一的XML pull解析器相关的错误。

package factory;

import android.util.Xml;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import bean.Book;


public class PULLParseTool extends XMLParseFactory {
    private List<Book> mBooksList;
    private Book book;

    @Override
    public void readXML(InputStream mInputStream) {
     XmlPullParser mXmlPullParser = Xml.newPullParser();
     try {
        mXmlPullParser.setInput(mInputStream, "UTF-8");
        int parserType = mXmlPullParser.getEventType();
        while (parserType!=XmlPullParser.END_DOCUMENT) {
            String tagName = mXmlPullParser.getName();
            switch (parserType) {
            case XmlPullParser.START_DOCUMENT:
                mBooksList = new ArrayList<Book>();
                break;
            case XmlPullParser.START_TAG:
                if (Book.BOOK.equals(tagName)) {
                    book = new Book();
                    book.setId(Integer.valueOf(mXmlPullParser.getAttributeValue("", Book.ID)));
                }
                else if(Book.NAME.equals(tagName)){
                    book.setName(mXmlPullParser.nextText());
                }else if(Book.PRICE.equals(tagName)){
                    book.setPrice(Float.valueOf(mXmlPullParser.nextText()));
                }
                break;
            case XmlPullParser.END_TAG:
                if (Book.BOOK.equals(tagName)) {
                    mBooksList.add(book);
                }

            }
                parserType = mXmlPullParser.next();
        }
    } catch (XmlPullParserException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }finally{
        if (mInputStream!=null) {
            try {
                mInputStream.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
    }

    @Override
    public void writeXML(String filePath) {
        // TODO Auto-generated method stub
        XmlSerializer mSerializer = Xml.newSerializer();
        FileOutputStream fos = null;
        try {
             fos =new FileOutputStream(filePath);
            mSerializer.setOutput(fos, "utf-8");
            mSerializer.startDocument("utf-8", true);
            mSerializer.startTag("",Book.BOOKS);
            for (Book book: getBookList()) {
                mSerializer.startTag("", Book.BOOK);
                mSerializer.attribute("", Book.ID,String.valueOf(book.getId()));

                mSerializer.startTag("", Book.NAME);
                mSerializer.text(book.getName());
                mSerializer.endTag("",Book.NAME);

                mSerializer.startTag("",Book.PRICE);
                mSerializer.text(String.valueOf(book.getPrice()));
                mSerializer.endTag("", Book.PRICE);

                mSerializer.endTag("", Book.BOOK);
            }
            mSerializer.endTag("", Book.BOOKS);
            mSerializer.endDocument();


        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalStateException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally{
            if (fos!=null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }

    }

    @Override
    public void setBookList(List<Book> mBookList) {
        if (this.mBooksList!=null&& this.mBooksList.size()>0) {
            this.mBooksList.clear();
        }
        this.mBooksList = mBookList;
    }

    @Override
    public List<Book> getBookList() {
        // TODO Auto-generated method stub
        return mBooksList;
    }

}

3.Sax解析
SAX(Simple API for XML)解析器是一种基于事件的解析器,事件驱动的流式解析方式是,从文件的开始顺序解析到文档的结束,不可暂停或倒退。它的核心是事件处理模式,主要是围绕着事件源以及事件处理器来工作的。当事件源产生事件后,调用事件处理器相应的处理方法,一个事件就可以得到处理。在事件源调用事件处理器中特定方法的时候,还要传递给事件处理器相应事件的状态信息,这样事件处理器才能够根据提供的事件信息来决定自己的行为。

SAX解析器的优点是解析速度快,占用内存少。非常适合在Android移动设备中使用。

SAX的工作原理:SAX的工作原理简单地说就是对文档进行顺序扫描,当扫描到文档(document)开始与结束、元素(element)开始与结束、文档(document)结束等地方时通知事件处理函数,由事件处理函数做相应动作,然后继续同样的扫描,直至文档结束。

在SAX接口中,事件源是org.xml.sax包中的XMLReader,它通过parser()方法来解析XML文档,并产生事件。事件处理器是org.xml.sax包中ContentHander、DTDHander、ErrorHandler,以及EntityResolver这4个接口。XMLReader通过相应事件处理器注册方法setXXXX()来完成的与ContentHander、DTDHander、ErrorHandler,以及EntityResolver这4个接口的连接。

常用的SAX接口和类:

Attrbutes:用于得到属性的个数、名字和值。 
ContentHandler:定义与文档本身关联的事件(例如,开始和结束标记)。大多数应用程序都注册这些事件。
DTDHandler:定义与DTD关联的事件。它没有定义足够的事件来完整地报告DTD。如果需要对DTD进行语法分析,请使用可选的DeclHandler。
DeclHandler是SAX的扩展。不是所有的语法分析器都支持它。
EntityResolver:定义与装入实体关联的事件。只有少数几个应用程序注册这些事件。
ErrorHandler:定义错误事件。许多应用程序注册这些事件以便用它们自己的方式报错。
DefaultHandler:它提供了这些接LI的缺省实现。在大多数情况下,为应用程序扩展DefaultHandler并覆盖相关的方法要比直接实现一个接口更容易。

详见下表:

可知,我们需要XmlReader 以及DefaultHandler来配合解析xml。

SaxHandler
package sax;
import org.xml.sax.Attributes; 
 import org.xml.sax.SAXException; 
 import org.xml.sax.helpers.DefaultHandler;import java.util.ArrayList; 
 import java.util.List;import bean.Book;
/** 
 * @author John 
 * Sax 
 */ 
 public class SaxHandler extends DefaultHandler{
private List<Book> mBookList;
private Book book;
private String targetElemant;

public List<Book> getBookList(){
    return mBookList;
}

/* (non-Javadoc)
 * @see org.xml.sax.helpers.DefaultHandler#startDocument()
 */
@Override

public void startDocument() throws SAXException {
    // TODO Auto-generated method stub
    super.startDocument();
    mBookList = new ArrayList<Book>();
}

@Override
public void endDocument() throws SAXException {
    // TODO Auto-generated method stub
    super.endDocument();
}

@Override
public void startElement(String uri, String localName, String qName,
        Attributes attributes) throws SAXException {
    // TODO Auto-generated method stub
    super.startElement(uri, localName, qName, attributes);
    if (qName.equals(Book.BOOK)) {
        book = new Book();
        book.setId(Integer.valueOf(attributes.getValue(Book.ID)));
    }
    targetElemant = localName;
}

@Override
public void endElement(String uri, String localName, String qName)
        throws SAXException {
    // TODO Auto-generated method stub
    super.endElement(uri, localName, qName);
    if (qName.equals(Book.BOOK)) {
        mBookList.add(book);

    }
    targetElemant = null;

}

@Override
public void characters(char[] ch, int start, int length)
        throws SAXException {
    // TODO Auto-generated method stub
    super.characters(ch, start, length);
    if (Book.NAME.equals(targetElemant)) {
        book.setName(new String(ch,start,length));
    }else if(Book.PRICE.equals(targetElemant)){
        book.setPrice(Float.valueOf(new String(ch,start,length)));
    }
}

}

SaxPullTool
package factory;

import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.util.List;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stream.StreamResult;

import bean.Book;
import sax.SaxHandler;

public class SAXParseTool extends XMLParseFactory{

    private SaxHandler mHandler= new SaxHandler();
    private List<Book> mBookList;



    @Override
    public void readXML(InputStream mInputStream) {

        try {
            SAXParserFactory factory = SAXParserFactory.newInstance();
            SAXParser parser = factory.newSAXParser();
            parser.parse(mInputStream, mHandler);
        } catch (ParserConfigurationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SAXException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally{
            if (mInputStream!=null) {
                try {
                    mInputStream.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }

        }


    }

    @Override
    public void writeXML(String filePath,List<Book> mBooks) {
        SAXTransformerFactory transFactory = (SAXTransformerFactory) SAXTransformerFactory.newInstance();
        TransformerHandler mHandler = null;
        try {
            mHandler = transFactory.newTransformerHandler();
            Transformer mTransformer = mHandler.getTransformer();
            mTransformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
            mTransformer.setOutputProperty(OutputKeys.INDENT, "yes");
            mTransformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");

            FileOutputStream fos = new FileOutputStream(filePath);
            OutputStreamWriter writer = new OutputStreamWriter(fos);
            Result result = new StreamResult(writer);
            mHandler.setResult(result);

            String uri = "";
            String localName = "";
            mHandler.startDocument();
            mHandler.startElement(uri, localName, Book.BOOKS, null);
            AttributesImpl attr = new AttributesImpl();
            char[] ch =null;
            for(Book book:mBooks){
                attr.clear();
                attr.addAttribute(uri, localName, Book.ID, "String", String.valueOf(book.getId()));
                mHandler.startElement(uri, localName, Book.BOOK, attr);

                mHandler.startElement(uri, localName, Book.NAME, null);
                ch = book.getName().toCharArray();
                mHandler.characters(ch, 0, ch.length);
                mHandler.endElement(uri, localName, Book.NAME);

                mHandler.startElement(uri, localName, Book.PRICE, null);
                ch = String.valueOf(book.getId()).toCharArray();
                mHandler.characters(ch, 0, ch.length);
                mHandler.endElement(uri, localName, Book.PRICE);

                mHandler.endElement(uri, localName, Book.BOOK);
            }
            mHandler.endElement(uri, localName, Book.BOOKS);
            mHandler.endDocument();

        } catch (TransformerConfigurationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }catch(FileNotFoundException e){
            e.printStackTrace();
        }catch (SAXException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }


    }

    @Override
    public void setBookList(List<Book> mBookList) {
        if (this.mBookList!=null && this.mBookList.size()>0) {
            this.mBookList.clear();
        }
        this.mBookList = mBookList;
    }

    @Override
    public List<Book> getBookList() {
        // TODO Auto-generated method stub
        return mHandler.getBookList();
    }

    @Override
    public void writeXML(String filePath) {
        // TODO Auto-generated method stub

    }

}

xml文件

<?xml version="1.0" encoding="utf-8"?>
<books>  
  <book id="1001">  
    <name>Thinking In Java</name>  
    <price>80.0</price>  
  </book>  
  <book id="1002">  
    <name>Core Java</name>  
    <price>90.0</price>  
  </book>  
  <book id="1003">  
    <name>Hello, Andriod</name>  
    <price>100.0</price>  
  </book>  
</books>

总结:
Dom解析是将xml文件以树形结构存放在内存中
优点:检索和更新效率会更高,解析速度快
缺点:解析和加载整个文档将会很耗资源,占用内存较多,不适合用于移动平台。如果XML文件的内容比较小,采用DOM是可行的

Pull解析是一个用于处理XML事件驱动的“推”模型
优点:解析速度快,占用内存少。它是从需求出发,根据用户需要的数据进行文件的加载和解析;
缺点:不能记录标签之间的关系,让你的应用程序自己处理,这样就增加了你程序的负担

SPull解析和ax解析类似, 解析器小巧轻便,解析速度快,简单易用,非常适合在Android移动设备中使用,Android系统内部在解析各种XML时也是用PULL解析器,Android官方推荐开发者们使用Pull解析技术。Pull相比Sax,他可以控制解析的结束。