Android/Java XML数据格式解析的两种方式

前言

网络上传输数据最常用的格式有两种:XML和JSON。
相比于JSON,XML优点是数据语义性强,很容易看的懂,容易书写。同时缺点也很明显,体积比JSON大,传输速率不及JSON。
即使如此,XML仍然是一种很重要的数据格式,如:Android开发过程中所有的资源文件都是XML格式。
博主前段时间面试一家公司,其中一道线下编程题就是实现XML构造器,还不允许用现有的XML框架。ORZ 给跪了,折腾了好久,虽然最后勉强算是完成任务,但是还是觉得跟一些框架相比实现的效果太差。

本文主要讲解Pull和SAX两种解析方式。这两种解析方式的jar是内置在android sdk中的所以不用导入,但是在Java中使用则需要导入。

本文两种方式以下面一段数据为例:

<apps>
    <app>
        <id>1</id>
        <name>google map</name>
        <version>1.0</version>
    </app>
    <app>
        <id>2</id>
        <name>google Chrome</name>
        <version>2.1</version>
    </app>
    <app>
        <id>3</id>
        <name>google play</name>
        <version>2.3</version>
    </app>
</apps>

Pull

直接上Pull方式的代码方法,注释已经写得很清楚了,直接看代码即可。
如果不懂的可以复制代码,运行一下,打印一些关键地方的变量的结果就行了。

/**
     * @param xml XML数据的String形式
     */
    private void pullXML(String xml) {
        try {
            //获取XmlPullParserFactory实例
            XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
            //根据实例获取XmlPullParser对象
            XmlPullParser xmlPullParser = factory.newPullParser();
            //设置xml数据
            xmlPullParser.setInput(new StringReader(xml));
            //获取当前的解析事件
            int eventType = xmlPullParser.getEventType();
            int id = 0;
            String name = null;
            double version = 0;
            //循环判断XmlPullParser.END_DOCUMENT解析工作是否完成
            while (eventType != XmlPullParser.END_DOCUMENT) {
                //获取当前节点的name
                String node = xmlPullParser.getName();
                switch (eventType) {
                    //对应节点解析开始XmlPullParser.START_TAG
                    case XmlPullParser.START_TAG:
                        if (node.equals("id")) {
                            id = Integer.parseInt(xmlPullParser.nextText());
                        } else if (node.equals("name")) {
                            name = xmlPullParser.nextText();
                        } else if (node.equals("version")) {
                            version = Double.parseDouble(xmlPullParser.nextText());
                        }
                        break;
                    //对应节点解析结束XmlPullParser.END_TAG
                    case XmlPullParser.END_TAG:
                        if (node.equals("app")) {
                            Log.i(TAG, "pullXML: " + id + "," + name + "," + version);
                        }
                        break;
                }
                //获取下一个解析事件
                eventType = xmlPullParser.next();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

这里写图片描述

虽然整个过程不是很难,但是逻辑特别容易混乱,尤其是XML格式的数据比较复杂的时候。

SAX

相比于Pull方式,SAX更复杂,需要新建一个解析类,但是SAX更容易操作。

新建Myhandler类继承DefaultHandler

很明显整个解析的流程就是在以下五个方法中进行的,相比于Pull方式更加直接明了。

public class MyHandler extends DefaultHandler {
    private static final String TAG = "MyHandler";
    String node;
    StringBuilder id;
    StringBuilder name;
    StringBuilder version;

    /**
     * 开始xml解析时调用,多用于初始化一些变量
     *
     * @throws SAXException
     */
    @Override
    public void startDocument() throws SAXException {
        id = new StringBuilder();
        name = new StringBuilder();
        version = new StringBuilder();
    }

    /**
     * 解析节点的时候调用,用于获取节点name
     *
     * @param uri
     * @param localName
     * @param qName
     * @param attributes
     * @throws SAXException
     */
    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes)
            throws SAXException {
        node = localName;
    }

    /**
     * 获取节点内容的时候调用,用于处理节点内容
     *
     * @param ch
     * @param start
     * @param length
     * @throws SAXException
     */
    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        if (node.equals("id")) {
            id.append(ch, start, length);
        } else if (node.equals("name")) {
            name.append(ch, start, length);
        } else if (node.equals("version")) {
            version.append(ch, start, length);
        }
    }

    /**
     * 完成某个节点解析时调用
     *
     * @param uri
     * @param localName
     * @param qName
     * @throws SAXException
     */
    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        if (localName.equals("app")) {
            Log.i(TAG, "endElement: " + id.toString().trim() + "," + name.toString().trim() + ","
                    + version.toString().trim());
            //清空Stringbuilder内容,否则还会影响下次调用
            id.setLength(0);
            name.setLength(0);
            version.setLength(0);
        }
    }

    /**
     * 完成整个xml解析后调用
     *
     * @throws SAXException
     */
    @Override
    public void endDocument() throws SAXException {
        super.endDocument();
    }
}
SAX过程

SAX方式的方法代码中注释依旧写得很清楚。
有什么地方不清晰的复制的代码运行一下,打印关键地方的结果就 很清楚了。

  private void saxXML(String xmlData) {
        try {
            //获取实例化对象
            SAXParserFactory factory = SAXParserFactory.newInstance();
            //获取XMLReader对象
            XMLReader reader = factory.newSAXParser().getXMLReader();
            //获取刚才MyHandler对象H
            MyHandler handler = new MyHandler();
            //将handler设置到XMLReader中
            reader.setContentHandler(handler);
            //执行xml解析
            reader.parse(new InputSource(new StringReader(xmlData)));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

这里写图片描述

总结

除Pull与SAX外还有DOM方式,由于用的不多此处不再详解。
Pull与SAX各有优缺,可以配合使用。
相信你看完本文,会觉XML格式数据解析相比于JSON还是很复杂的,尤其是在有GSON框架后,JSON的解析不要太简单。(JSON格式数据解析及GSON框架的使用详解)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值