Android解析XML数据和Json数据

本文主要参考以下三篇文章,排名不分先后(瞬间觉得高大上):

http://www.cnblogs.com/devinzhang/archive/2012/01/16/2323668.html

http://blog.youkuaiyun.com/tkwxty/article/details/34474501

http://blog.youkuaiyun.com/lmj623565791/article/details/47911083

很久没更blog了,今天写一写Android常见的两种数据解析—XML和Json。

XML数据解析

Android中经常用到两种方法来解析XML,SAX和PULL。另外还有一种DOM方式,表示没用过,这里就不介绍了,有兴趣的同学可以看看我列出的参考文章的第一篇或者自己度娘。

下面贴一下数据源,来自 w3school

<food>
<name>Belgian Waffles</name>
<price>$5.95</price>
<description>
two of our famous Belgian Waffles with plenty of real maple syrup
</description>
<calories>650</calories>
</food>

先说PULL方式,个人觉得这种方式比较简单,符合自己写代码时的逻辑。

public class PullParser implements FoodParser {
    List<Food> mList = null;
    Food mFood = null;
    @Override
    public List<Food> parser(InputStream in) throws Exception {
        XmlPullParser mParser = Xml.newPullParser();
        mParser.setInput(in,"UTF-8");
        //取得当前标签的类型
        int eventType = mParser.getEventType();
        //根据标签类型判断执行的语句
        while (eventType != XmlPullParser.END_DOCUMENT){
            switch(eventType){
                //XML文件开始
                case XmlPullParser.START_DOCUMENT:
                    mList = new ArrayList<Food>();
                    break;
                //标签开始
                case XmlPullParser.START_TAG:
                    if (mParser.getName().equals("food")){
                        mFood = new Food();
                    }else if (mParser.getName().equals("name")){
                        eventType = mParser.next();
                        mFood.setName(mParser.getText());
                    }else if (mParser.getName().equals("price")){
                        eventType = mParser.next();
                        mFood.setPrice(mParser.getText());
                    }else if (mParser.getName().equals("description")){
                        eventType = mParser.next();
                        mFood.setDescription(mParser.getText());
                    }else if (mParser.getName().equals("calories")){
                        eventType = mParser.next();
                        mFood.setCalories(Integer.parseInt(mParser.getText()));
                    }
                    break;
                //标签结束
                case XmlPullParser.END_TAG:
                    if (mParser.getName().equals("food")){
                        mList.add(mFood);
                        mFood = null;
                    }
                    break;
            }
            eventType = mParser.next();
        }
        return mList;
    }
}

怎么样逻辑是不是很清晰,XML没有到结尾就一直读取,在开始的时候初始化List,然后根据标签名来获取内容。

再来说SAX方式。这种方式个人感觉麻烦了点,因为要额外定义一个handler来处理XML文件。

public class SaxParser implements FoodParser{
    @Override
    public List<Food> parser(InputStream in) throws Exception{
        SAXParserFactory mFactory = SAXParserFactory.newInstance();
        SAXParser mParser = mFactory.newSAXParser();
        MyHandler mHandler = new MyHandler();
        mParser.parse(in,mHandler);
        return mHandler.getFoods();
    }

    private static class MyHandler extends DefaultHandler {

        private List<Food> foods;
        private Food food;
        private StringBuilder builder;

        //返回解析后得到的Food对象集合  
        public List<Food> getFoods() {
            return foods;
        }
        //文档开始
        @Override
        public void startDocument() throws SAXException {
            super.startDocument();
            foods = new ArrayList<Food>();
            builder = new StringBuilder();

        }
        //元素标签开始
        @Override
        public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
            super.startElement(uri, localName, qName, attributes);
            if (localName.equals("food")) {
                food = new Food();
            }
            builder.setLength(0);   //将字符长度设置为0 以便重新开始读取元素内的字符节点  
        }
        //解析内容
        @Override
        public void characters(char[] ch, int start, int length) throws SAXException {
            super.characters(ch, start, length);
            builder.append(ch, start, length);  //将读取的字符数组追加到builder中  
        }
        //标签结束
        @Override
        public void endElement(String uri, String localName, String qName) throws SAXException {
            super.endElement(uri, localName, qName);
            if (localName.equals("description")) {
                food.setDescription(builder.toString());
            } else if (localName.equals("name")) {
                food.setName(builder.toString());
            } else if (localName.equals("price")) {
                food.setPrice(builder.toString());
            } else if(localName.equals("calories")){
                food.setCalories(Integer.parseInt(builder.toString()));
            }
            else if (localName.equals("food")) {
                foods.add(food);
            }
        }
    }
}

虽然SAX的逻辑也是十分清晰简单,和PULL类似,不过要额外定义一个类,个人表示不爽。

利用Gson解析Json数据

解析Json数据在Android经常使用Gson库来实现,因为它简单方便、简单方便、简单方便,重要的事情说三遍。

Json数据只有三种形式,值,对象,数组。不过通常我们遇到的数据都是嵌套型的,就是对象里面的某个属性可能又是一个对象或者数组。

怎样使用Gson解析嵌套型数据?如果是属性是一个对象,你就需要额外定义一个类来表示这个对象。如果属性是一个数组,你就需要使用一个List表示。

下面看看Json数据,来自慕课网

{"status":1,
"data":[{"id":1,"name":"Tony\u8001\u5e08\u804ashell\u2014\u2014\u73af\u5883\u53d8\u91cf\u914d\u7f6e\u6587\u4ef6","picSmall":"http:\/\/img.mukewang.com\/55237dcc0001128c06000338-300-170.jpg","picBig":"http:\/\/img.mukewang.com\/55237dcc0001128c06000338.jpg","description":"\u4e3a\u4f60\u5e26\u6765shell\u4e2d\u7684\u73af\u5883\u53d8\u91cf\u914d\u7f6e\u6587\u4ef6","learner":12312},
{"id":2,"name":"\u6570\u5b66\u77e5\u8bc6\u5728CSS\u52a8\u753b\u4e2d\u7684\u5e94\u7528","picSmall":"http:\/\/img.mukewang.com\/55249cf30001ae8a06000338-300-170.jpg","picBig":"http:\/\/img.mukewang.com\/55249cf30001ae8a06000338.jpg","description":"\u6570\u5b66\u77e5\u8bc6\u4e0eCSS\u7ed3\u5408\u5b9e\u73b0\u9177\u70ab\u6548\u679c","learner":45625}]}

像上面这个Json数据首先是一个对象,对象里面有两个属性,status和data。status是一个值,data是一个数组,这个数组的元素是对象。所以我们要这样定义表示Json的类。

public class JsonDatas {
    int status;
    List<Course> data;

    public List<Course> getData() {
        return data;
    }

    public void setData(List<Course> data) {
        this.data = data;
    }

    public int getStatus() {
        return status;
    }

    public void setStatus(int status) {
        this.status = status;
    }

    @Override
    public String toString() {
        return "JsonDatas{" +
                "data=" + data +
                ", status=" + status +
                '}';
    }
}

注意到了吗,类的名称可以随便命名,但是属性的名称一定要与Json的属性名称一致。上面我使用了List表示Json中的数组,因为数组里面的元素是一个对象,我又另外声明一个类来表示这个对象。

public class Course {
    private int id;
    private String name;
    private String picSmall;
    private String picBig;
    private String description;
    private int leaner;

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getLeaner() {
        return leaner;
    }

    public void setLeaner(int leaner) {
        this.leaner = leaner;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPicBig() {
        return picBig;
    }

    public void setPicBig(String picBig) {
        this.picBig = picBig;
    }

    public String getPicSmall() {
        return picSmall;
    }

    public void setPicSmall(String picSmall) {
        this.picSmall = picSmall;
    }

    @Override
    public String toString() {
        return "Course{" +
                "description='" + description + '\'' +
                ", id=" + id +
                ", name='" + name + '\'' +
                ", picSmall='" + picSmall + '\'' +
                ", picBig='" + picBig + '\'' +
                ", leaner=" + leaner +
                '}';
    }
}

属性名一定要一致。接下来就是解析了,如果你使用的是原生的API来解释这段数据,你要额外写很多代码,而使用Gson只要这样:

//得到整个对象
 JsonDatas data = new Gson().fromJson(body, JsonDatas.class);
//得到data属性的数据
 final List<Course> courses = data.getData();

只要两行代码,就将所有的数据封装到了你定义的类之中。使用Gson你关心的只是怎么去定义你的类,不用考虑解析和填充的问题。

因为数据源都在网上,使用了OkHttp获取数据源,关于OkHttp的用法请参考第三篇参考文章

最后给出源码地址:http://download.youkuaiyun.com/detail/u013983998/9196075

使用方法:打开Android Studio,新建一个Poroject,再File -> New ->Import Module

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值