XMl和JSON数据解析

在网络上传输数据时最常用的格式有两种:XML和JSON格式。XML格式的数据扩展性比较好,格式比较统一;JSON数据格式比较简单,体积比较小,在实际的项目中应用比较多。
对于XML解析方式挺多的,比如Pull解析,SAX解析和Dom解析。现在逐一用一个案例说明该如何使用。
假设解析的数据格式如下:

String responeData = "<apps>
    <app>
        <id>1</id>
        <name>Google</name>
        <version>1.0</version>
    </app>
    <app>
        <id>2</id>
        <name>Chrome</name>
        <version>2.1</version>
    </app>
    <app>
        <id>3</id>
        <name>WeChat</name>
        <version>3.5</version>
    </app>
</apps>"

使用Pull的方式进行解析:

      try {
            XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
            //将xml数据设置进去
            parser.setInput(new StringReader(responeString));
            //获取当前解析事件
            int eventType = parser.getEventType();
            String id = "";
            String name = "";
            String version = "";
            //eventType != XmlPullParser.END_DOCUMENT 说明解析工作还没完成
            while (eventType != XmlPullParser.END_DOCUMENT){
                //获取当前节点名字
                String nodeName = parser.getName();
                switch (eventType){
                    case XmlPullParser.START_TAG:
                        //开始解析某个节点
                        if ("id".equals(nodeName)){
                            //获取节点内具体的内容
                            id = parser.nextText();
                        }else if ("name".equals(nodeName)){
                            name = parser.nextText();
                        }else if ("version".equals(nodeName)){
                            version = parser.nextText();
                        }
                        break;
                    case XmlPullParser.END_TAG:
                        //完成解析某个节点
                        if ("app".equals(nodeName)){
                            Log.d(TAG, "parseXMLWithPull: id = "+id);
                            Log.d(TAG, "parseXMLWithPull: name = "+name);
                            Log.d(TAG, "parseXMLWithPull: version = "+version);
                        }
                        break;
                }
                //获取下一个解析事件
                eventType = parser.next();
            }
        } catch (XmlPullParserException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

Pull解析的可以主动从解析器中获取事件,正是由于这个元素我们可以在满足某个条件时不再获取事件,从而结束解析,也就是说Pull解析可以不完全解析整个XML文件,可以只解析到我们所需要的地方,这样可以更节省资源,也是Pull解析最大的特点之一。
对于SAX解析,对比Pull解析用法要稍微复杂一点,但是语意方面比较清楚,具体简单用法如下:
先创建一个新类MyHandler继承自DefaultHandler,并重写父类5个方法:

public class MyHandler extends DefaultHandler {
    private static final String TAG = "MyHandler";
    private String nodeName;
    private StringBuilder id;
    private StringBuilder name;
    private StringBuilder version;
    @Override
    public void startDocument() throws SAXException {
        //开始XML解析的时候调用
        super.startDocument();
        id = new StringBuilder();
        name = new StringBuilder();
        version = new StringBuilder();
    }

    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        //开始解析某个节点的时候调用
        super.startElement(uri, localName, qName, attributes);
        //记录当前节点名字
        nodeName = localName;
    }

    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        //获取节点中内容时调用
        super.characters(ch, start, length);
        if ("id".equals(nodeName)){
            id.append(ch,start,length);
        }else if ("name".equals(nodeName)){
            name.append(ch,start,length);
        }else if ("version".equals(nodeName)){
            version.append(ch,start,length);
        }
    }

    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        //开始结束解析某个节点时调用
        super.endElement(uri, localName, qName);
        if ("app".equals(localName)){
            //目前的id,name,version都有可能包含回车或换行符的,所以需要trim一下
            Log.d(TAG, "endElement: id = "+id.toString().trim());
            Log.d(TAG, "endElement: name = "+name.toString().trim());
            Log.d(TAG, "endElement: version = "+version.toString().trim());
            //清空stringBuidler
            id.setLength(0);
            name.setLength(0);
            version.setLength(0);
        }
    }

    @Override
    public void endDocument() throws SAXException {
        //结束整个XML文件解析时调用
        super.endDocument();
    }
}

在外部使用的代码如下:

        try {
            SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser();
            XMLReader xmlReader = saxParser.getXMLReader();
            //将MyHandler设置到XMLReader中
            xmlReader.setContentHandler(new MyHandler());
            //开始执行解析
            xmlReader.parse(new InputSource(new StringReader(responeString)));
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

SAX解析的原理是加载一点,读取一点,处理一点,对内存要求比较低,适合大容量文件的读取。SAX解析只能从上往下,按顺序读取,不能往回读。
Dom解析的简单用例如下:

        try {
            DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
            Document doc = builder.parse(new ByteArrayInputStream(responeString.getBytes()));
            //获取根结点
            Element element = doc.getDocumentElement();
            //获取app节点列表
            NodeList nodeList = element.getElementsByTagName("app");
            for (int i = 0; i < nodeList.getLength(); i++) {
                //app节点下的子节点
                Node item = nodeList.item(i);
                NodeList childNodes = item.getChildNodes();
                for (int j =0;j<childNodes.getLength();j++) {
                    Node child = childNodes.item(j);
                    if (child.getNodeType() == Node.ELEMENT_NODE) {
                        Element childElement = (Element) child;
                        //获取节点名称
                        String nodeName = childElement.getNodeName();
                        //获取节点内容
                        String nodeValue = childElement.getFirstChild().getNodeValue();
                        if ("id".equals(nodeName)) {
                            Log.d(TAG, "parseXMLWithDom: id = " + nodeValue);
                        } else if ("name".equals(nodeName)) {
                            Log.d(TAG, "parseXMLWithDom: name = " + nodeValue);
                        } else if ("version".equals(nodeName)) {
                            Log.d(TAG, "parseXMLWithDom: version = " + nodeValue);
                        }
                    }
                }

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

其中还有很多Dom API就不细说了。
Dom解析的原理是一次性加载XML文档到内存,在内存中构建Document树,对内存要求比较高,不适合大容量XML文件读取,容易导致内存溢出。而且Dom解析可以进行任意增删改,可以读取任意位置的数据,甚至可以往回读。

其中JSON解析就是JSONArray和JSONObject的组合,以上述为例:

String jsonString = "[
    {
        "id": "1",
        "name": "Google",
        "version": "1.0"
    },
    {
        "id": "2",
        "name": "Chrome",
        "version": "2.1"
    },
    {
        "id": "3",
        "name": "WeChat",
        "version": "3.5"
    }
]";

//开始解析json字符串
 try {
            JSONArray jsonArray = new JSONArray(jsonString);
            for (int i=0;i<jsonArray.length();i++){
                JSONObject jsonObject = jsonArray.getJSONObject(i);
                String id = jsonObject.getString("id");
                String name = jsonObject.getString("name");
                String version = jsonObject.getString("version");

                Log.d(TAG, "parseJSON: id =" +id +" name = "+name +" version = "+version);

            }
 } catch (JSONException e) {
            e.printStackTrace();
 }

除此之外还有很多第三方框架可以进行json解析,想Gson,fastJson等,这里就不一一叙述了。

=========================================================
对于Gson框架解析JSON数组会稍微麻烦一些,这样我们就可以借助TypeToken将期望转换的类型传入到fromJson中,如下:

List<App> apps = gson.fromJson(responString,new TypeToken<List<App>>(){}.getType())
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值