android xml 解析

Introduce

xml 是目前使用范围最广的数据传输类型。这几天在弄的一个项目,就是用xml来进行数据传输的,所以特地把所有的xml 解析方式进行学习总结一下。

DOM 方式解析

Dom方式解析是将整个xml文档一次性全部读取出来,进行解析。可以想象在读入的时候,就已经将整个文档解析好了,之后可以任意地去读取出来了。

优点

这种方式很显然,读取出来方便,写入也方便。

缺点

一次性就将整个文档读取了,so,比较耗费内存。如果文档特别大,那就比较窘迫了。所以该解析方式适合文档相对较小的。对于手机,显然不合适。

代码Sample

xml文档:

<?xml version="1.0" encoding="utf-8"?>
<sample>
<item id="0" >DOM</item>
<item id="1" >SAX</item>
<item id="2" >Pull</item>
</sample>

以下代码都是从网上参考来的,仅供参考。

public static List<channel> getChannelList(InputStream stream)
{
    List<channel> list=new ArrayList<channel>();

    //得到 DocumentBuilderFactory 对象, 由该对象可以得到 DocumentBuilder 对象
    DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();

    try {
        //得到DocumentBuilder对象
        DocumentBuilder builder=factory.newDocumentBuilder();
        //得到代表整个xml的Document对象
        Document document=builder.parse(stream);
        //得到 "根节点"
        Element root=document.getDocumentElement();
        //获取根节点的所有items的节点
        NodeList items=root.getElementsByTagName("item");  
        //遍历所有节点
        for(int i=0;i<items.getLength();i++)
        {
            channel chann=new channel();
            Element item=(Element)items.item(i);
            chann.setId(item.getAttribute("id"));
            chann.setUrl(item.getAttribute("url"));
            chann.setName(item.getFirstChild().getNodeValue());
            list.add(chann);
        }

    } 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();
    }

    return list;
}

###SAX 方式解析
sax 方式解析,是基于事件驱动的。它分成两部分,一个是xml解析器,一个事件处理器。分别对应XMLReader 和 Handler。

优点

sax不用一次性读取整个文档,很显然基于事件驱动,可以不用一次性耗费那么内存。而且,SAX解析方式更加具有结构性将xml解析器跟事件处理区分开,有人说会更麻烦,个人觉得见人见智吧,其实结构性好了,更方便使用。

缺点

一个节点一个节点地读入,如果遇到文档小,显然没有Dom那么方便。

Sample

private List<Sample> getSampleList() throws ParserConfigurationException, SAXException, IOException
{
    //实例化一个SAXParserFactory对象
    SAXParserFactory factory=SAXParserFactory.newInstance();
    SAXParser parser;
    //实例化SAXParser对象,创建XMLReader对象,解析器
    parser=factory.newSAXParser();
    XMLReader xmlReader=parser.getXMLReader();
    //实例化handler,事件处理器
    SAXPraserHelper helperHandler=new SAXPraserHelper();
    //解析器注册事件
    xmlReader.setContentHandler(helperHandler);
    //读取文件流
    InputStream stream=getResources().openRawResource(R.raw.channels);
    InputSource is=new InputSource(stream);
    //解析文件
    xmlReader.parse(is);
    return helperHandler.getList();
}

handle

public class SAXPraserHelper extends DefaultHandler {

final int ITEM = 0x0005;

List<Sample> list;
channel chann;
int currentState = 0;

public List<Sample> getList() {
    return list;
}

/*
 * 接口字符块通知
*/
@Override
public void characters(char[] ch, int start, int length)
        throws SAXException {
    // TODO Auto-generated method stub
// super.characters(ch, start, length);
    String theString = String.valueOf(ch, start, length);
    if (currentState != 0) {
        chann.setName(theString);
        currentState = 0;
    }
    return;
}

/*
 * 接收文档结束通知
*/
@Override
public void endDocument() throws SAXException {
    // TODO Auto-generated method stub
    super.endDocument();
}

/*
 * 接收标签结束通知
*/
@Override
public void endElement(String uri, String localName, String qName)
        throws SAXException {
    // TODO Auto-generated method stub
    if (localName.equals("item"))
        list.add(chann);
}

/*
 * 文档开始通知
*/
@Override
public void startDocument() throws SAXException {
    // TODO Auto-generated method stub
    list = new ArrayList<Sample>();
}

/*
 * 标签开始通知
*/
@Override
public void startElement(String uri, String localName, String qName,
        Attributes attributes) throws SAXException {
    // TODO Auto-generated method stub
    chann = new channel();
    if (localName.equals("item")) {
        for (int i = 0; i < attributes.getLength(); i++) {
            if (attributes.getLocalName(i).equals("id")) {
                chann.setId(attributes.getValue(i));
            } else if (attributes.getLocalName(i).equals("url")) {
                chann.setUrl(attributes.getValue(i));
            }
        }
        currentState = ITEM;
        return;
    }
    currentState = 0;
    return;
}

###Pull 方式解析
也是基于事件驱动的,但是与sax不同。它是开始解析后,可以一次一次地调用next来获取下一个解析事件,这样就多了自主地控制了。

优点

从某些角度上来看,Pull显然是要简单些。

缺点

跟SAX 优点类似吧。

Sample

private List<Map<String, String>> getData() {
    List<Map<String, String>> list = new ArrayList<Map<String, String>>();
    XmlResourceParser xrp = getResources().getXml(R.xml.channels);

    try {
        // 直到文档的结尾处
        while (xrp.getEventType() != XmlResourceParser.END_DOCUMENT) {
            // 如果遇到了开始标签
            if (xrp.getEventType() == XmlResourceParser.START_TAG) {
                String tagName = xrp.getName();// 获取标签的名字
                if (tagName.equals("item")) {
                    Map<String, String> map = new HashMap<String, String>();
                    String id = xrp.getAttributeValue(null, "id");// 通过属性名来获取属性值
                    map.put("id", id);
                    map.put("name", xrp.nextText());
                    list.add(map);
                }
            }
            xrp.next();// 获取解析下一个事件
        }
    } catch (XmlPullParserException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    return list;
}

###参考

  1. http://www.cnblogs.com/JerryWang1991/archive/2012/02/24/2365507.html

小悟诗词

穷则变,变则通,通则久 —《周易·系辞下》