Android网络应用(三)——网络数据解析

在网络上传输数据时最常用的格式有两种,XML 和 JSON.

解析 XML 格式数据

<apps>
    <app>
        <id>1</id>
        <name>Google Maps</name>
        <version>1.0</version>
    </app>
    <app>
        <id>2</id>
        <name>Chrome</name>
        <version>2.1</version>
    </app>
    <app>
        <id>3</id>
        <name>Google Play</name>
        <version>2.3</version>
    </app>
</apps>

Pull 解析方式——XmlPullParserFactory、XmlPullParser

比如,利用HttpGet 直接获取该网页上面的如上xml文件内容,并获取到响应response。自定义parseXMLWithPull(response)方法。

private void parseXMLWithPull(String xmlData) {
    try {
        XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
        XmlPullParser xmlPullParser = factory.newPullParser();
        xmlPullParser.setInput(new StringReader(xmlData));
        int eventType = xmlPullParser.getEventType();
        String id = "";
        String name = "";
        String version = "";
        while (eventType != XmlPullParser.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();
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

SAX 解析方式

AX 解析也是一种特别常用的 XML 解析方式,虽然它的用法比 Pull 解析要复杂一些,但在语义方面会更加的清楚。

创建

1、新建一个类继承自 DefaultHandler,并重写父类的五个方法。

public class MyHandler extends DefaultHandler {
    @Override
    public void startDocument() throws SAXException {
    }
    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
    }
    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
    }
    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
    }
    @Override
    public void endDocument() throws SAXException {
    }
}

startDocument()方法会在开始 XML 解析的时候调用,startElement()方法会在开始解析某个结点的时候调用,characters()方法会在获取结点中内容的时候调用,endElement()方法会在完成解析某个结点的时候调用,endDocument()方法会在完成整个 XML 解析的时候调用。其中,startElement()、characters()和 endElement()这三个方法是有参数的,从 XML 中解析出的数据就会以参数的形式传入到这些方法中。需要注意的是,在获取结点中的内容时,characters()方法可能会被调用多次,一些换行符也被当作内容解析出来,我们需要针对这种情况在代码中做好控制。

实例
//解析类实现
public class ContentHandler extends DefaultHandler {
    private String nodeName;
    private StringBuilder id;
    private StringBuilder name;
    private StringBuilder version;
    @Override
    public void startDocument() throws SAXException {
        id = new StringBuilder();
        name = new StringBuilder();
        version = new StringBuilder();
    }
    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        // 记录当前结点名
        nodeName = localName;
    }
    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        // 根据当前的结点名判断将内容添加到哪一个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);
        }
    }
    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        if ("app".equals(localName)) {
            Log.d("ContentHandler", "id is " + id.toString().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 endDocument() throws SAXException {
    }
}

每当开始解析某个结点的时候, startElement()方法就会得到调用,其中 localName 参数记录着当前结点的名字,这里我们把它记录下来。接着在解析结点中具体内容的时候就会调用 characters()方法,我们会根据当前的结点名进行判断,将解析出的内容添加到哪一个StringBuilder 对象中。最后在 endElement()方法中进行判断,如果 app 结点已经解析完成,就打印出 id、name 和 version 的内容。需要注意的是,目前 id、name 和 version 中都可能是包括回车或换行符的,因此在打印之前我们还需要调用一下 trim()方法,并且打印完成后还要将 StringBuilder 的内容清空掉,不然的话会影响下一次内容的读取。

private void parseXMLWithSAX(String xmlData) {
    try {
        SAXParserFactory factory = SAXParserFactory.newInstance();
        XMLReader xmlReader = factory.newSAXParser().getXMLReader();
        ContentHandler handler = new ContentHandler();
        // 将ContentHandler的实例设置到XMLReader中
        xmlReader.setContentHandler(handler);
        // 开始执行解析
        xmlReader.parse(new InputSource(new StringReader(xmlData)));
    } catch (Exception e) {
        e.printStackTrace();
    }
}

先是创建了一个 SAXParserFactory 的对象,然后再获取到XMLReader 对象,接着将我们编写的 ContentHandler 的实例设置到 XMLReader 中,最后调用 parse()方法开始执行解析就好了。

解析JSON格式数据

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

JSON 格式的内容:

[{"id":"5","version":"5.5","name":"Angry Birds"},
{"id":"6","version":"7.0","name":"Clash of Clans"},
{"id":"7","version":"3.5","name":"Hey Day"}]

使用 JSONObject

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 (Exception e) {
        e.printStackTrace();
    }
}

在服务器中定义的是一个 JSON 数组,因此这里首先是将服务器返回的数据传入到了一个 JSONArray 对象中。然后循环遍历这个 JSONArray,从中取出的每一个元素都是一个 JSONObject 对象,每个 JSONObject 对象中又会包含 id、name 和version 这些数据。接下来只需要调用 getString()方法将这些数据取出,并打印出来即可。

使用 GSON

GSON 并没有被添加到 Android 官方的 API 中,因此如果想要使用这个功能的话,则必须要在项目中添加一个 GSON 的 Jar 包。首先我们需要将 GSON 的资源压缩包下载下来,下载地址是:http://code.google.com/p/google-gson/downloads/list。其中 gson-2.2.4.jar 这个文件就是我们所需要的了,现在将它拷贝到 NetworkTest 项目的libs 目录下,GSON 库就会自动添加到 NetworkTest 项目中了,

解析单个json数据

GSON最神奇之处:可以将一段 JSON 格式的字符串自动映射成一个对象,从而不需要我们再手动去编写代码进行解析了。

比如:

//比如说一段 JSON 格式的数据如下所示:
{"name":"Tom","age":20}

//以定义一个 Person 类,并加入 name 和 age 这两个字段,然后只需简单地调用如下代码就可以将 //JSON 数据自动解析成一个 Person 对象了
Gson gson = new Gson();
Person person = gson.fromJson(jsonData, Person.class);

解析JSON数组——TypeToken

List<Person> people = gson.fromJson(jsonData, new TypeToken<List<Person>>(){}.getType());
实际应用
//类对象
public class App {
    private String id;
    private String name;
    private String version;
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getVersion() {
        return version;
    }
    public void setVersion(String version) {
        this.version = version;
    }
}
private void parseJSONWithGSON(String jsonData) {
    Gson gson = new Gson();
    List<App> appList = gson.fromJson(jsonData, new TypeToken<List<App>>() {}.getType());
    for (App app : appList) {
        Log.d("MainActivity", "id is " + app.getId());
        Log.d("MainActivity", "name is " + app.getName());
        Log.d("MainActivity", "version is " + app.getVersion());
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值