Android 网络编程之 XML 和 JSON 解析

通常情况下,每个需要访问网络的应用程序都会有一个自己的服务器,我们可以向服务器提交数据,也可以从服务器上获取数据。网络上传输数据时最常用的格式有两种:XML 和 JSON。

这里以之前的一篇文章 Android网络访问之HttpURLConnection和HttpClient 为基础,继续添加代码,介绍 XML 和 JSON 的解析方式。

0. 搭建 Web 服务器

这里首先需要搭建了一个简单的 Web 服务器,在这个服务器上提供一段 XML 格式文本和一段 JSON 格式文本,然后在程序里访问这个服务器,分别对其进行解析。

关于如何下载安装 Apache 服务器,这里有篇文章写得很详细: 如何从Apache官网下载windows版apache服务器

0.1 添加 XML 文件

安装好之后,在其文件夹下的 htdocs 文件夹中新建一个名为 get_data.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>

此时在浏览器中访问 http://127.0.0.1/get_data.xml 这个网址,显示如下:
1

0.2 添加 JSON 文件

在 htdocs 文件夹中新建一个名为 get_data.json 的文件,添加如下代码:

[{"id":"5", "version":"5.5", "name":"Angry Brid"},
{"id":"6", "version":"7.0", "name":"Super Mario"},
{"id":"7", "version":"9.0", "name":"Plants vs. Zombies"}]

在浏览器访问 http://127.0.0.1/get_data.json,显示如下:
3

注意需要开启相应服务。

1. 解析 XML 格式数据

解析 XML 格式数据方法有很多种,这里介绍常用的两种:Pull 方式和 SAX 方式(此外 DOM 解析方式也比较常用)。
修改MainActivity 中 sendRequestWithHttpClient() 方法中的代码,将 http 请求网址改为 http://10.0.2.2/get_data.xml (PS: 10.0.2.2
对模拟器来说就是电脑本机 IP 地址)。

1.1 Pull

创建 parseXMLWithPull() 方法,并在 sendRequestWithHttpClient() 方法中调用它即可,且无需再发送 Message。代码如下:

    /**
     * 解析 XML 格式数据(Pull 解析方式)
     */
    private void parseXMLWithPull(String xmlData) {
        try {
            XmlPullParserFactory factory = XmlPullParserFactory.newInstance();// 获取 XmlPullParserFactory实例
            XmlPullParser xmlPullParser = factory.newPullParser();// 得到 XmlPullParser 的对象
            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.e("MainActivity", "id is " + id);
                        Log.e("MainActivity", "name is " + name);
                        Log.e("MainActivity", "version is " + version);
                    }
                    break;
                }
                default:
                    break;
                }
                eventType = xmlPullParser.next();
            }
        } catch (XmlPullParserException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

运行程序,LogCat 中显示如下:
5
说明已经将 XML 文件中的内容成功解析出来了。

1.2 SAX

SAX 解析较 Pull 方式略复杂(通常会新建一个类继承自 DefaultHandler,并重写父类的5个方法),但在语义方面更清晰。
新建一个类 ContentHandler 继承自 DefaultHandler,代码如下:

    /**
     * 解析 XML 格式数据(SAX 解析方式)
     */
public class ContentHandler extends DefaultHandler {

    private String nodeName;

    private StringBuilder id;

    private StringBuilder name;

    private StringBuilder version;

    @Override
    public void startDocument() throws SAXException {// 开始解析XML时调用
        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 {
        // 获取结点内容时调用。
        // 在获取结点内容时,本方法可能被调用多次,一些换行符也被当做内容解析出来,需要做好控制(如本例中的trim方法)

        // 根据当前的结点名判断将内容添加到哪一个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.e("ContentHandler", "id is " + id.toString().trim());
            Log.e("ContentHandler", "name is " + name.toString().trim());
            Log.e("ContentHandler", "version is " + version.toString().trim());

            // 清空StringBuilder
            id.setLength(0);
            name.setLength(0);
            version.setLength(0);
        }
    }

    @Override
    public void endDocument() throws SAXException {
        // 完成解析XML时调用
    }
}

接下来在 MainActivity 中添加 parseXMLWithSAX() 方法,并在 sendRequestWithHttpClient() 方法中调用它即可,代码如下:

    /**
     * 解析 XML 格式数据(SAX 解析方式)
     */
    private void parseXMLWithSAX(String xmlData) {
        SAXParserFactory factory = SAXParserFactory.newInstance();
        try {
            XMLReader xmlReader = factory.newSAXParser().getXMLReader();
            ContentHandler handler = new ContentHandler();

            xmlReader.setContentHandler(handler);// 将ContentHandler的实例设置到XMLReader中

            xmlReader.parse(new InputSource(new StringReader(xmlData)));// 开始执行解析
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

运行程序,效果同上。

2. 解析 JSON 格式数据

JSON 与 XML 相比的优缺点:

  • 优点:体积小,省流量。
  • 缺点:语义性较差。

解析 JSON 格式的数据也有多种方法,这里介绍两种:JSONObject 和 GSON。

2.1 JSONObject

在 MainActivity 中创建 parseJSONWithJSONObject() 方法,并在 sendRequestWithHttpClient() 方法中调用它即可,同样无需发送 Message。代码如下:

    /**
     * 解析 JSON 格式的数据(JSONObject 解析方式)
     */
    private void parseJSONWithJSONObject(String jsonData) {
        try {
            JSONArray jsonArray = new JSONArray(jsonData);// 将服务器返回的数据传入 JSONArray 对象中
            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.e("MainActivity", "id is " + id);
                Log.e("MainActivity", "name is " + name);
                Log.e("MainActivity", "version is " + version);
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

注意要将 http 请求网址改为 http://10.0.2.2/get_data.json

可以看到这种方式代码更简单。运行程序,LogCat 中显示如下:

4

2.2 GSON

GSON 并未添加到 Android 的官方 API 中,因此若想使用的话需要在项目中添加 GSON 的 jar 包(下载 后将其添加到 libs 文件夹下即可)。

新建一个 APP 类,代码如下:

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;
    }

}

在 MainActivity 中创建 parseJSONWithGSON() 方法,并在 sendRequestWithHttpClient() 方法中调用它即可,同样无需发送 Message。代码如下:

    /**
     * 解析 JSON 格式的数据(GSON 解析方式)
     */
    private void parseJSONWithGSON(String jsonData) {
        Gson gson = new Gson();

        // 借助TypeToken将期望解析成的数据类型传入到fromJson()方法中
        List<App> appList = gson.fromJson(jsonData, new TypeToken<List<App>>() {}.getType());

        for (App app : appList) {
            Log.e("MainActivity", "id is " + app.getId());
            Log.e("MainActivity", "name is " + app.getName());
            Log.e("MainActivity", "version is " + app.getVersion());
        }
    }

运行程序,结果同上。

源码下载

《第一行代码》 学习笔记。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值