XML解析(三),PULL解析XML

昨天写了【XML解析(一)】SAX解析XML 和【XML解析(二)】DOM解析XML两篇文章,有兴趣的朋友可以去看一下,今天我们来学习一下PULL解析XML,刚好可以跟SAX和DOM解析XML的两种方式对比学习,其实Android里面解析XML最常用的也就这三种,而这三种并不一定拘泥于Android开发,同样也可以用在J2EE开发中,下面我们进入本篇文章的学习。

一、概述

 PULL?,拉?,肯定不是什么的简称了,PULL是Android内置的解析XML的方式,但是并不局限与Android,也可以是J2EE。
 PULL解析具有与SAX类似的特点,提供了与SAX类似的事件,比如:开始元素事件和结束元素事件,看过【XML解析(一)】SAX解析XML 的朋友或者使用过SAX解析XML的朋友是否还记得SAX解析的几个重要的事件吗?这里我简单复习一下SAX的几个重要的事件

SAX的几个重要的事件

  1. startDocument():XML文档解析开始的时候触发,只会调用一次,我们可以在这里做一些解析前的准备工作
  2. startElement():元素或标签解析开始的时候触发
  3. characters:startElement触发后立即触发
  4. endElement():元素或标签解析结束的时候触发
  5. endDocument():XML文档解析结束后触发,只会触发一次

PULL的事件(仅有五个)

  1. START_DOCUMENT:开始文档解析
  2. START_TAG:解析元素
  3. TEXT:解析文本
  4. END_TAG:结束元素解析
  5. END_DOCUMENT:结束文档解析

下面做个事件的简单对比(类似)

PULL SAX
START_DOCUMEN startDocument
START_TAG startElement
TEXT characters
END_TAG endElement
END_DOCUMENT endElement


 Pull只有一个重要的事件next()

PULL解析XML的优点:

  • 解析速度快
  • 占用内存小,消耗的资源少
  • 简单,易集成(Android)
  • 支持生成,修改,删除XML文件

PULL解析适用于:

  • Android
  • 速度快,效率高的J2EE

大概了解了pull,下面我们通过一个简单的Demo简单学习一下pull 解析 xml

二、PULL解析XML实战

 新建一个Android项目PullParseXmlDemo,因为android集成pull,无需导入jar包,为了方便这里将整个demo的目录结构给出,在文章末尾将会把demo贴上,方便大家下载导入eclipse测试。

目录结构:

XML解析(三),PULL解析XML_第1张图片

PULL解析步骤:

  1. 加载xml资源
  2. 得到pull解析器XmlPullParser
  3. 使用解析器解析

1、新建xml测试文件,uses.xml

<?xml version="1.0" encoding="UTF-8"?>
<users>
    <user id="1">
        <name>毕向东</name>
        <password>bxd123</password>
    </user>
    <user id="2">
        <name>韩顺平</name>
        <password>hsp123</password>
    </user>
    <user id="3">
        <name>马士兵</name>
        <password>msb123</password>
    </user>
</users>

2、新建JavaBean,User.java

package com.example.pullparsexmldemp;


public class User{
    private long id;
    private String name;
    private String password;

    public long getId() {
        return id;
    }
    public void setId(long id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
}

3、新建一个解析核心方法getUsers()封装到一个工具类中,XmlParseUtils.java

public static List<User> getUsers() throws Exception {
        List<User> users = null;
        User user = null;
        // 加载xml资源
        InputStream is = XmlParseUtils.class.getClassLoader()
                .getResourceAsStream("users.xml");
        // 得到Pull解析器
        XmlPullParser pullParser = Xml.newPullParser();
        // 设置Xml输入流
        pullParser.setInput(is, "utf-8");
        int event = pullParser.getEventType(); // 触发第一个事件

        while (event != XmlPullParser.END_DOCUMENT) {
            switch (event) {
                case XmlPullParser.START_DOCUMENT:
                    Log.e(TAG, pullParser.getName()+"----START_DOCUMENT");
                    users = new ArrayList<User>();
                    break;
                case XmlPullParser.START_TAG:
                    if ("user".equals(pullParser.getName())) {
                        Log.e(TAG, pullParser.getName()+"----START_TAG");
                        user = new User();
                        int id = Integer.valueOf(pullParser.getAttributeValue(0));
                        user.setId(id);
                    }
                    if (user != null) {
                        if ("name".equals(pullParser.getName())) {
                            Log.e(TAG, pullParser.getName()+"----START_TAG");
                            // 注意是nextText()取标签之间的文本,而不是getText()
                            // getText()返回的是当前触发事件的字符描述
                            user.setName(pullParser.nextText());
                        }
                        if ("password".equals(pullParser.getName())) {
                            Log.e(TAG, pullParser.getName()+"----START_TAG");
                            user.setPassword(pullParser.nextText());
                        }
                    }
                    break;
                case XmlPullParser.END_TAG:
                    if ("user".equals(pullParser.getName())) {
                        Log.e(TAG, pullParser.getName()+"----END_TAG");
                        users.add(user);
                        user = null;
                    }
                    break;
                }
            event = pullParser.next();
        }
        if(event == XmlPullParser.END_DOCUMENT){
            Log.e(TAG, pullParser.getName()+"----END_DOCUMENT");
        }
        return users;
    }

 这里的解析过程和SAX解析过程非常类似,就不多说了,这里先将日志打印,方便我们下面分析pull解析原理。

OK,PULL解析XML的核心就在getUsers()方法中了,接下来是测试是否解析成功了

Android的单元测试:

参考:【XML解析(一)】SAX解析XML

测试结果:

OK,可以看到使用PULL成功解析XML,下面我们看一下下面的日志来简单分析一下PULL解析的过程:

XML解析(三),PULL解析XML_第2张图片

 可以看到,当文档解析开始的时候START_DOCUMENT事件触发,仅触发了一次,接下来没遇到一个新的标签的开始都触发了STAET_TAG时间,每个标签的结束都触发了END_TAG,所以START_TAGEND_TAG事件触发的次数和标签是成对出现的,即有开始就有结束,最后文档解析结束END_DOCUMENT触发。原理过程分析结束,前面我们说了PULL不仅可以解析XML,还可以生成,修改,删除XML。下面我们通过PULL生成XML做个测试

三、PULL生成XML

PULL生成XML步骤:

  1. 设置输出源
  2. 得到xml序列化类xmlSerializer
  3. 使用序列化类生成XML

第一步:在工具类中添加一个方法createXml(List users,OutputStream outputStream)

        XmlSerializer xmlSerializer = Xml.newSerializer();
        // 设置输出源及编码
        xmlSerializer.setOutput(outputStream,"utf-8");
        // 参数1:设置编码
        // 参数2:standalone 用来表示该文件是否呼叫其它外部的文件。若值是 true 
        // 表示没有呼叫外部文件,若值是 false 则表示有呼叫外部文件。默认值是true
        xmlSerializer.startDocument("utf-8", true);
        // 生成users开始标签
        xmlSerializer.startTag(null, "users");
        for(User user : users){ // 每循环一次生成一个user
            // 生成user标签和id属性
            xmlSerializer.startTag(null, "user");
            xmlSerializer.attribute(null, "id", user.getId()+"");

            // 生成name开始标签
            xmlSerializer.startTag(null, "name");
            // 设置name标签的文本
            xmlSerializer.text(user.getName());
            // 闭合name标签
            xmlSerializer.endTag(null, "name");

            // ...
            xmlSerializer.startTag(null, "password");
            xmlSerializer.text(user.getPassword());
            xmlSerializer.endTag(null, "password");

            // 闭合user标签
            xmlSerializer.endTag(null, "user");
        }
        xmlSerializer.endTag(null, "users"); // 闭合users标签
        xmlSerializer.endDocument(); // 结束文档
        outputStream.flush(); // 将所有缓冲区的数据全部写到文件中
        outputStream.close(); // 一定不要忘了关闭流
    }

 注释说的差不多了,是不是觉得PULL生成XML文件好简单。

说明:startDocument的两个参数分别设置生成的xml文件头部的encoding和standalone属性,下面我们看了生成的文件就知道了。

第二步、在PullParseXmlTest.java中添加一个测试方法testCreateXml()

/** * 测试生成xml * @throws Exception */
    public void testCreateXml() throws Exception{
        // this.getContext().getFilesDir()得到的是/data/data/files/
        File file = new File(this.getContext().getFilesDir(),"users.xml");
        FileOutputStream fileOutputStream = new FileOutputStream(file);
        List<User> users = new ArrayList<User>();
        User user1 = new User();
        user1.setId(1);
        user1.setName("毕向东");
        user1.setPassword("bxd123");
        users.add(user1);
        User user2 = new User();
        user2.setId(2);
        user2.setName("韩顺平");
        user2.setPassword("hsp123");
        users.add(user2);
        User user3 = new User();
        user3.setId(3);
        user3.setName("马士兵");
        user3.setPassword("msb123");
        users.add(user3);

        XmlParseUtils.createXml(users, fileOutputStream);
    }

 没什么好说的,直接运行测试

下面我们看看生成的users.xml文件

1、打开DDMS视图:

XML解析(三),PULL解析XML_第3张图片

2、找到当前应用的files文件夹

XML解析(三),PULL解析XML_第4张图片

3、将生成的xml导出

XML解析(三),PULL解析XML_第5张图片

 这里也可以用adb pull [remote] [local]:命令文件

adb命令参考:adb常用命令

用编辑器打开users.xml可以看到(格式化后):

<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<users>
    <user id="1">
        <name>毕向东</name>
        <password>bxd123</password>
    </user>
    <user id="2">
        <name>韩顺平</name>
        <password>hsp123</password>
    </user>
    <user id="3">
        <name>马士兵</name>
        <password>msb123</password>
    </user>
</users>

 注意看xml文件头,encodingstandalone属性都是startDocument()的两个参数知道指定的

<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
  • 关于PULL,SAX,DOM解析XML
     PULL解析XML与SAX类似,具有解析速度快,效率高,占用资源少的特点,而DOM解析XML虽然简单,可以随机访问文档树的任何一个节点,可以知道整个文档树结构和整个文档树的所有信息,但正是由于在内存中要形成这样的一个文档树,所以导致了解析速度慢,占用资源大,这对于资源多,不要求效率的场合是一种不错的选择,但是对于Android等内存小,cpu资源宝贵的移动设备来说是致命的,SAX虽然速度快,占用资源,但由于无法修改,生成XML,所以这就是为什么Android集成PULL,而不是SAX和DOM的原因吧。

总结:XML解析,生成,修改XML都好简单,Android集成PULL,掌握PULL必须的。

上面这篇文章由于个人理解,如果有理解错的地方,欢迎指出,与君共勉,一起进步。

demo下载地址:http://download.csdn.net/detail/ydxlt/9330427

你可能感兴趣的:(xml,android,Android开发,pull)