文档章节

Anroid开发之Xml的解析

YH_猿员猿
 YH_猿员猿
发布于 2016/07/21 17:31
字数 1719
阅读 3
收藏 0

行业解决方案、产品招募中!想赚钱就来传!>>>

    在前面的一个博客中我们了解了json数据的解析,现在我们来实现对xml格式的数据的解析,xml是一种可扩展标记语言,是由标签组成的。方便我们读取数据。
    xml的解析有三种方式,DOM解析,SAX解析,PULL解析。

  1. DOM解析XML文件时,会将XML文件所有内容都读取到内存中,然后再遍历XML文件树,检索需要的数据。DOM解析XML有很大的缺陷,对内存的消耗比较大,影响系统的性能,所以我这里没有详细讲DOM解析。
  2. SAX解析是一种占用内存少,且解析速度快的解析器,它采用事件驱动,它不需要解析整个文档,而是按照顺序,检索XML文件是否符合XML的语法,当符合时会触发相应的回调函数。这些函数是在ContentHander中,我们可以重写这些方法来实现我们对数据的解析。
  3. Pull解析是一种可以解析部分XML文件的解析方式,当我们只需要XML文件中的一部分数据时,用这种方法是非常好的。Pull解析和SAX解析类似,SAX解析器工作方式是自动的将事件推入注册的事件处理器进行处理,因此你不能控制事件的处理主动结束,而Pull解析的工作方式为允许你的应用程序代码主动从解析器获取事件,因此我们可以在获取了我们需要的数据时,主动结束解析。

SAX解析
SAX解析的主要是重写ContentHander中回调方法,在其中主要的是:

  1. startDocument:当遇到文档时候触发事件。
  2. startElement:当遇到开始标签时触发。
  3. endElement:当遇到结束标签时触发。
  4. characters:当遇到xml内容时触发。
    这里写图片描述

上面是我自己建的一个xml文件,命名为students.xml,并将它放在assets文件夹下。

1.我首先定义了一个student类对象,用来存放解析出来的xml数据

public class Student {

    private Long Id;
    private String Name;
    private String Speciality;
    private Long QQ;
    public Student() {
    }
    //省略了get和set方法
}

2.实例化一个SAX工厂,并获取SAX解析器,读取xml文件,创建回调函数

protected List<Student> parserXML() {
        //实例化一个SAX解析工厂
        SAXParserFactory factory = SAXParserFactory.newInstance();
        List<Student> studnets = null;
        //获取XML解析器
        try {
            XMLReader reader = factory.newSAXParser().getXMLReader();
            studnets = new ArrayList<Student>();
            //设置回调函数,这里是我自定义的回调函数
            reader.setContentHandler(new StudentHander(studnets));
            //读取Assets下的student.xml文件
            reader.parse(new InputSource(SAXXMLActivity.this.
                    getResources().getAssets().open("students.xml")));
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return studnets;

3.自定义StudentHander回调函数,继承自DefaultHander;在回调方法里解析出自己需要的数据。其中preTAG用来存储当前节点名称,在endElement中要记得滞空。

public class StudentHander extends DefaultHandler {
    private String preTAG;
    private List<Student> ListStudent;
    private Student stu;
    public StudentHander() {
    }

    public StudentHander(List<Student> listStudent) {
        super();
        ListStudent = listStudent;
    }


    //开始解析文档
    @Override
    public void startDocument() throws SAXException {
        Log.i("----->", "开始解析文档!");
        super.startDocument();
    }
    //开始解析文档元素
    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        Log.i("localName----->", localName);
        preTAG = localName;
        if ("student".equals(localName)) {
            stu = new Student();
            //将ID保存在stu中
            stu.setId(Long.parseLong(attributes.getValue(0)));
            for (int i = 0; i < attributes.getLength(); i++) {
                Log.i("attribute----->", String.valueOf(stu.getId()));
            }
        }
        //这句话记得要执行
        super.startElement(uri, localName, qName, attributes);
    }
    @Override
    public void endDocument() throws SAXException {
        Log.i("----->", "文档结束");
        super.endDocument();

    }
    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        preTAG = "";
        if ("student".equals(localName)) {
            ListStudent.add(stu);
            Log.i("----->", "一个元素解析完成!");
        }
        super.endElement(uri, localName, qName);
    }
    //解析节点文本内容
    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        String str;
        //找出元素中的name节点
        if ("name".equals(preTAG)) {
            str = new String(ch,start,length);
            stu.setName(str);
            Log.i("name=", str);
        }else if("speciality".equals(preTAG)){
            str = new String(ch,start,length);
            stu.setSpeciality(str);
            Log.i("speciality=", str);
        }else if("qq".equals(preTAG)){
            str = new String(ch,start,length);
            stu.setQQ(Long.parseLong(str));
            Log.i("qq=", str);
        }

        super.characters(ch, start, length);
    }
    public void setListStudent(List<Student> listStudent) {
        ListStudent = listStudent;
    }
    public List<Student> getListStudent() {
        return ListStudent;
    }
}

这样我们就解析出xml的整个数据了,并在回调函数中将数据保存到了数组对象students中,我们查看一下打印出的log,分析一下SAX的解析过程。
这里写图片描述

我们可以看出这种按顺序解析XML文件标签的方式,完全符合回调函数中的说明。清晰明了。


Pull解析
pull解析和我们上面的SAX解析方法有些类似,Pull解析也提供了类似SAX的事件:

  1. START_DOCUMENT:开始文档;
  2. START_TAG:开始元素;
  3. TEXT:遇到元素内容;
  4. END_TAG:结束元素
  5. END_DOCUMENT:结束文档

Android系统提供了Pull解析的包org.xmlpull.v1,里面有PUll解析工厂类XMLPullParserFactory,和PULL解析器XmlParser。我们实例化工厂类,并获取xml解析器,接着XmlParser实例就可以调用getEventType()和next()等方法主动提取事件,并根据提取的事件做数据的处理。

PULL解析器有两种获取方法:

  1. 通过工厂类XMLPullParserFactory
  2. 通过Android实用工具类
protected List<Student> parserXML() {
        //初始化一个List<student>变量,用于存放student成员
        List<Student> studnets = null;
        //初始化student对象,用于存储每一个节点的信息
        Student stu = null;

        try {
            //打开资源文件
            InputStream inputStream = PullXMLActivity.this.getResources()
                    .getAssets().open("students.xml");
            //创建XmlParser有两种方法
            //方法一:使用工厂类XmlPullParserFactory
            XmlPullParserFactory pullFactory = XmlPullParserFactory.newInstance();
            XmlPullParser xmlPullParser = pullFactory.newPullParser();
            /* * //方法二:使用Android提供的实用工具类android.util.Xml //XmlPullParser xmlPullParser = Xml.newPullParser(); //设置输入字节流为UTF-8编码 * */
            xmlPullParser.setInput(inputStream, "utf-8");
            //取得事件类型,用于开始时的判断
            int eventType = xmlPullParser.getEventType();
            //循环遍历整个文件直到结束
            while(eventType != XmlPullParser.END_DOCUMENT){
                /* * 输出log显示事件类型 * START_DOCUMENT:0 * */
                Log.i("--->event", eventType+" ");
                //用于存储节点名称
                String localName = "";
                switch (eventType) {
                case XmlPullParser.START_DOCUMENT:
                    //碰到文档开头则实例化students变量,并输出log
                    studnets = new ArrayList<Student>();
                    Log.e("Pull---->", "start document");
                    break;
                case XmlPullParser.START_TAG:
                    localName = xmlPullParser.getName();
                    if ("student".equals(xmlPullParser.getName())) {
                        stu = new Student();
                        //将ID保存到stu中
                        stu.setId(Long.parseLong(xmlPullParser.getAttributeValue(0)));
                        Log.e("Pull----->", stu.getId()+"");
                    }else if(stu != null){
                        //声明一个变量用于存储节点文本
                        String currentData = null;
                        if ("name".equals(xmlPullParser.getName())) {
                            /* * 注意这里nextText()的使用:当前事件为START-TAG * 如果接下来是文本,就会返回当前的文本内容;如果下一个事件是End_TAG * 就会返回空字符串;否则抛出一个yichang */
                            currentData = xmlPullParser.nextText();
                            //存储name的信息
                            stu.setName(currentData);

                        }else if("speciality".equals(xmlPullParser.getName())){
                            currentData = xmlPullParser.nextText();
                            //存储专业信息
                            stu.setSpeciality(currentData);
                        }else if("qq".equals(xmlPullParser.getName())){
                            currentData = xmlPullParser.nextText();
                            //存储专业信息
                            stu.setQQ(Long.parseLong(currentData));
                        }
                    }
                    break;
                case XmlPullParser.END_TAG:
                    localName = xmlPullParser.getName();
                    Log.e("Pull----->", localName);
                    if ("student".equals(localName) && stu != null) {
                        studnets.add(stu);
                        stu = null;
                    }
                    break;
                default:
                    break;
                }
                //解析下一事件
                eventType = xmlPullParser.next();
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (XmlPullParserException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return studnets;
    }

这里也打印出log贴出来并做出了分析
这里写图片描述

总结:
SAX和PULL解析器虽然在代码上可能写的有些复杂,但是它们的解析效率,和思维逻辑的清晰都是非常好的,值得我们在软件开发中使用。

YH_猿员猿
粉丝 0
博文 12
码字总数 0
作品 0
徐汇
程序员
私信 提问
加载中
请先登录后再评论。
浅入浅出Android(003):使用TextView类构造文本控件

基础: TextView是无法供编辑的。 当我们新建一个项目MyTextView时候,默认的布局(/res/layout/activity_main.xml)中已经有了一个TextView: <TextView 运行效果如下: 修改其文本内容...

樂天
2014/03/22
601
1
beego API开发以及自动化文档

beego API开发以及自动化文档 beego1.3版本已经在上个星期发布了,但是还是有很多人不了解如何来进行开发,也是在一步一步的测试中开发,期间QQ群里面很多人都问我如何开发,我的业余时间实在...

astaxie
2014/06/25
2.7W
22
Nutch学习笔记4-Nutch 1.7 的 索引篇 ElasticSearch

上一篇讲解了爬取和分析的流程,很重要的收获就是: 解析过程中,会根据页面的ContentType获得一系列的注册解析器, 依次调用每个解析器,当其中一个解析成功后就返回,否则继续执行下一个解...

强子哥哥
2014/06/26
712
0
Web开发组件管理器--Bower

Bower 是一个针对Web开发的包管理器。该工具主要用来帮助用户轻松安装CSS、JavaScript、图像等相关包,并管理这些包之间的依赖。 功能有些类似于Component。不同之处是,Component是围绕Git...

匿名
2013/02/01
1.2W
2
XLSX读写库--EPPlus

EPPlus 是使用Open Office XML格式(xlsx)读写Excel 2007 / 2010文件的.net开发库。 EPPlus 支持: 单元格范围 单元格样式(Border, Color, Fill, Font, Number, Alignments) Charts 图片 形状...

匿名
2013/02/01
1W
2

没有更多内容

加载失败,请刷新页面

加载更多

PHP实现RabbitMQ消息队列

先安装PHP对应的RabbitMQ,这里用的是 php_amqp 不同的扩展实现方式会有细微的差异. php扩展地址: http://pecl.php.net/package/amqp 具体以官网为准 http://www.rabbitmq.com/getstarted.htm...

PHP圈子
29分钟前
20
0
pdd笔试题

拼多多提前批的笔试没有报名,但昨天听伙伴们说很难,所以一共4道题,挑了2道会的,自己编了一下。 #include<iostream>#include<vector>#include<algorithm>using namespace std;int ma...

osc_tylqml9v
29分钟前
0
0
拓扑排序算法

/** * 拓扑排序算法,拓扑都是有向无环图 * 使用场景:编译的时候,比如,springboot启动的时候要读取docker系统环境变量,还要读取各配置文件按照顺序 * 还有比如,a的包依赖...

osc_94gn551r
31分钟前
0
0
巨微代理MS1581蓝牙无线收发器

上海巨微MS1581包含8位单片机和低功耗、低成本的BLE收发器,内部集成了发射机、接收机、GFSK调制解调器和BLE基带处理。遵循BLE广播通道通信,具有成本低、体积小、控制方便等优点。巨微代理英...

英尚微电子
31分钟前
12
0
链接测试(内部)

1、长链 https://chelun.eclicks.cn/web/information?info_tid=156984 - 文章test http://cjjl-h5-test.chelun.com/2020/big/index.html - 以小博大test 2、scheme : 钱包 supercoach://myw......

osc_hwc3munb
32分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部