第六章 解析网络数据

解析XML数据和JSON数据

        首先要知道的一个问题 —— 数据到底是以什么样的格式在网络上传输的呢?随便传递一段文本肯定不行,因为另一方根本不知道这段文本的用途是什么。因此,我们会在网络上传输一些格式化后的数据,这种数据有一定的结构规格和语义,另一方收到数据消息之后就可以按照相同的结构规格进行解析,进而取出它想要的那部分内容。

        网络上常用的传输数据的格式有两种 —— XML和JSON。

一、解析XML格式数据

1.1 Pull解析方法

        上一节课学到发送Http请求并接收到来自服务器的数据,接收到的是一段String,这里赋值给变量response。接下来,我们要做的就是对response进行解析:
1. 首先要获取到一个XmlPullParserFactory的实例,并借助这个实例得到XmlPullParser对象,然后调用XmlPullParser的setInput()方法将服务器返回的XML数据设置进去就可以开始解析了;
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
XmlPullParser xmlPullParser = factory.newPullParser();
xmlPullParser.setInput(new StringReader(xmlData));
2. 解析过程通过getEventType()可以得到当前的解析时间,然后在一个while循环中逐个解析;
<span style="white-space:pre">	</span>    int eventType = xmlPullParser.getEventType();
            String id = "";
            String name = "";
            String version = "";
            while (eventType != XmlPullParser.END_DOCUMENT) {    //eventType!=END_DOCUMENT说明解析工作还没完成
                String nodeName = xmlPullParser.getName();
                switch (eventType) {
                    //开始解析某个节点
                    case XmlPullParser.START_TAG:
                        if ("id".equals(nodeName)) {
                            id = xmlPullParser.nextText();
                        } else if ("name".equals(nodeName)) {
                            name = xmlPullParser.nextText();
                        } else if ("version".equals(nodeName)) {
                            version = xmlPullParser.nextText();
                        }
                        break;
                    //完成解析某个结点
                    case XmlPullParser.END_TAG:
                        if ("app".equals(nodeName)) {
                            Log.d("MainActivity", "id is" + id);
                            Log.d("MainActivity", "name is" + name);
                            Log.d("MainActivity", "version is" + version);
                        }
                        break;
                    default:
                        break;
                }
                eventType = xmlPullParser.next();       //调用next()方法获取下一个解析事件
            }
解析前的xml数据和解析后的数据如下(左图是网络上打开的xml文件,右图是解析后在LogCat中的打印日志):

1.2 SAX解析方法

1. 要使用SAX方法,我们要新建一个继承自DefaultHandler,并重写父类的五个方法,如下:
public class SAXParseHandler extends DefaultHandler {

    private String nodeName;
    //分别定义了StringBuilder对象
    private StringBuilder id;
    private StringBuilder name;
    private StringBuilder version;

    //开始解析xml的时候调用
    @Override
    public void startDocument() throws SAXException {
        super.startDocument();
        //初始化各个StringBuilder
        id = new StringBuilder();
        name = new StringBuilder();
        version = new StringBuilder();
    }

    @Override
    public void endDocument() throws SAXException {
        super.endDocument();
    }

    //开始解析某个结点(元素)时调用
    @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 endElement(String uri, String localName, String qName) throws SAXException {
        super.endElement(uri, localName, qName);
        //判断如果app结点已经解析完成,就在日志中打印出来
        if ("app".equals(localName)){
            Log.d("ContentHandler","id is"+id.toString().trim());   //因为id中可能含有回车或换行符的,用trim()移除字符串两侧的空白字符
            Log.d("ContentHandler","name is"+name.toString().trim());
            Log.d("ContentHandler","version is"+version.toString().trim());
            //最后要将StringBuilder清空,不然会影响下一次的内容读取
            id.setLength(0);
            name.setLength(0);
            version.setLength(0);
        }
    }

    //获取结点中内容的时候调用
    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        super.characters(ch, start, length);
        //根据当前的结点名判断将内容添加到哪一个StringBuilder对象中
        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);
        }
    }
}
2. 创建ContentHelper后,在MAinActivity中的封装并调用一个 parseXMLWithSAX(String xmlData) 方法,用来解析数据:
SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
SAXParser saxParser = saxParserFactory.newSAXParser();
XMLReader xmlReader = saxParser.getXMLReader();

SAXParseHandler saxParseHandler = new SAXParseHandler();
xmlReader.setContentHandler(saxParseHandler);       //将saxParseHandler十二只到XMLReader中
try {
            xmlReader.parse(new InputSource(new StringReader(xmlData)));
        } catch (IOException e) {
            e.printStackTrace();
        }
        运行后,在LogCat中的日志的结果和上面用Pull是一样的。

二、解析JSON格式数据

        比起XML,JSON的主要优势在于它的体积更小,在网络上传输的时候可以更省流量。但缺点在于,它的语义性差,看起来不如XML直观。

2.1 使用JSONObject

        这里创建一个parseJSONWithJSONObject(String jsonData) 方法,来解析JSON数据:
    private void parseJSONWithJSONObject(String jsonData){
        try {
            JSONArray jsonArray = new JSONArray(jsonData);
            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("MainActivity","id is"+id);
                Log.d("MainActivity","name is"+name);
                Log.d("MainActivity","version is"+version);
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }
        首先我们要看jsonData是一个什么样的数据(见下图),由于我们要获得的网络数据是一个JSON数据,因此这里首先是将服务器返回的数据传入到了一个JSONArray对象中。然后遍历数组,从中取出的每一个元素都是一个JSONObject对象,每个JSONObject对象又包含id、name、version这些数据,再调用getString方法将这些数据取出即可。

2.2 使用GSON

        GSON是谷歌提供的一个开源库,让JSON的解析变得前所未有的简单。首先,我们要在项目中添加一个GSON的Jar包,通过AS设置中的plugins搜索添加即可。
        GSON的神奇在于它可以将一段JSON格式的数据自动映射成一个对象,从而不需要手动去编写代码解析了。比如一段JSON格式的数据如下:
{"name":"Tom","age":20}
       我们只需要定义一个Person类,并加入name和age这两个字段,然后调用如下代码即可将JSON数据自动解析成一个Person对象:
Gson gson = new Gson();
Person person = gson.fromJson(jsonData,Person.class);
TIP:对于有些比较复杂的JSON数据,我们可能需要定义很多类来解析,这里提供一个插件——GsonFormat,可以将JSON自动转成Java类(好东西,能够省不少时间呐!)


拾遗:

1. http://www.jsons.cn —— 一个神奇的网站,可以进行JSON的校验、格式化、生成实体类(和上文中GsonFormat功能相似,个人感觉这个更好用)等功能,能够大大提供工作效率;



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值