Android数据Json解析之开源jar类Gson解析

来源:互联网 发布:风靡美国华人网络的菜 编辑:程序博客网 时间:2024/05/21 06:26

这里简要地记述一下对xml数据解析的三种使用方法,方便日后温习。

XML文档解析可以采用的方法:DOM(Document Object Module)、SAX(Simple API for XML)和PULL方式。DOM和SAX解析方式都已经集成在Java里面了,Sun公司提供了Java API for XML Parsing(JAXP)接口来使用DOM和SAX,我们可以使用任何与JAXP兼容的XML解析器。JAXP接口包含了三个包:
  (1)org.w3c.dom W3C推荐的用于XML标准规划文档对象模型的接口。 
  (2)org.xml.sax  用于对XML进行语法分析的事件驱动的XML简单API(SAX)
  (3)javax.xml.parsers解析器工厂工具,可以获得并配置特殊的特殊语法分析器。
  而Pull解析方式则需要引入第三方工具包(目前我找到的最新版kxml2-2.3.0.jar,好像还没api文档可供下载http://kxml.objectweb.org)。

DOM方式把一切都当作一个节点,文档节点、元素节点、文本节点、注释节点etc。它把整个XML文档当作一个Document对象,解析时需要把整个xml文档加载到内存中,解析完成后根据XML文档的节点结构生成文件树。可在程序中随意存取文件树,没有次数限制。显然DOM方式并不适合解析大的XML文档,太耗内存。

sax方式具有解析器和事件处理器,解析器负责读取XML文档和向事件处理器发送事件(充当事件源),事件处理器负责对发送的事件响应和进行XML文档处理。SAX方式采用流处理方式,边解析边触发相应的事件。不需要把整个xml文档加载进内存,边解析边丢弃,解析速度快,占用内存少,很适合移动开发。SAX是层次型的解析,只能依次对xml文档的数据流处理一遍,不支持对数据的任意存取操作(自己用变量保存解析结果另说)。使用sax方式不需要事先知道xml文档的每一个节点名称,主要的工作是写事件处理类。

pull方式跟sax方式很像,也是事件驱动型的。pull方式的结构非常简单,最重要的两个方法就是next()和nextToken(),最常用的几个属性【parser是XmlPullParser解析器对象】:
   parser.START DOCUMENT
  parser.START_TAG
  parser.TEXT
  parser.END_TAG
  parser.END_DOCUMENT

下面贴一下主要的示例代码片段:
首先在tomcat服务器端放一个xml文档person.xml,内容如下:

<?xml version="1.0" encoding="utf-8"?><persons>    <person id="23">        <name>叫兽</name>        <age>21</age>    </person>    <person id="20">        <name>李四</name>        <age>25</age>    </person>    <person id="10">        <name>淫贼</name>        <age>20</age>    </person></persons>
在客户端程序里面需要写一个类来操作得到的xml节点信息,这里统一都用Person.java类:
public class Person {    private int id;    private String name;    private int age;    public int getId() {        return id;    }    public void setId(int id) {        this.id = id;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }    @Override    public String toString() {        return "Person [age=" + age + ", id=" + id + ", name=" + name + "]";    }}

统一使用HttpUtils.java类从tomcat服务器上面得到xml文档的数据流
public class HttpUtils {    /**     * 根据路径获取服务器端的xml文件数据流     * @param path xml所在的服务器文件路径     * @return InputStream xml文件的数据流     */    public static InputStream getXML(String path) {        InputStream inputStream = null;        try {            URL url = new URL(path);            if (url != null) {                HttpURLConnection connection = (HttpURLConnection) url                        .openConnection();                connection.setConnectTimeout(3000);                connection.setDoInput(true);                connection.setRequestMethod("GET");                int code = connection.getResponseCode();                if (code == 200) {//连接成功                    inputStream = connection.getInputStream();                    return inputStream;                }            }        } catch (Exception e) {            // TODO: handle exception            e.printStackTrace();        }        return null;    }}
DOM方式解析xml文档的主要操作:
public List<Person> getPersons(InputStream inputStream) throws Exception{        List<Person> list=new ArrayList<Person>();        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();// 创建一个document解析的工厂        DocumentBuilder builder = factory.newDocumentBuilder();//dom解析器,此时整个xml文件已经保存在内存中        Document document = builder.parse(inputStream);//解析xml文件流获得文档对象        Element element = document.getDocumentElement();// 获得文档元素节点//      element.getFirstChild()//逐个节点往下读        NodeList personNodeList = element.getElementsByTagName("person");        int len=personNodeList.getLength();        for (int i = 0; i < len; i++) {            Element personElement = (Element) personNodeList.item(i);            Person person = new Person();            person.setId(Integer.parseInt(personElement.getAttribute("id")));            NodeList childNodes = personElement.getChildNodes();            for (int j = 0; j < childNodes.getLength(); j++) {                if (childNodes.item(j).getNodeType() == Node.ELEMENT_NODE) {//判断节点类型为元素节点                    if ("name".equals(childNodes.item(j).getNodeName())) {//name子节点                        person.setName(childNodes.item(j).getFirstChild()                                .getNodeValue());                    } else if ("age".equals(childNodes.item(j).getNodeName())) {//age子节点                        person.setAge(Integer.parseInt(childNodes.item(j)                                .getFirstChild().getNodeValue()));                    }                }            }            list.add(person);        }        return list;    }

DOM方式的测试类Test.java

public class Test {    /**     * @param args     */    public static void main(String[] args) {        // TODO Auto-generated method stub        String path="http://localhost:8080/myhttp/person.xml";        InputStream inputStream=HttpUtils.getXML(path);        DomParseService service=new DomParseService();        try {            List<Person> list=service.getPersons(inputStream);            for(Person person:list){                System.out.println(person.toString());            }        } catch (Exception e) {            // TODO Auto-generated catch block            e.printStackTrace();        }    }}

SAX方式主要操作集中在事件处理器上(代码有点多,省略),简要说说这个事件处理类MyHandler.java的实现。这个类需要继承DefaultHandler类,同时在类的构造函数中传入当前解析的节点名称。主要是重写以下几个方法来处理事件:
1.public void startDocument() throws SAXException {//接收文档开始时触发}
2.public void startElement(String uri, String localName, String qName,Attributes attributes) throws SAXException {//接收第一个元素时触发事件
3.public void characters(char[] ch, int start, int length)throws SAXException {//接收元素中字符数据时出发,这里面处理xml文档信息}
4.public void endElement(String uri, String localName, String qName)throws SAXException {//遇到文档结束标记时触发}

代码在上一篇文章中。SAX


PUll方式解析的主要类PullXMLTools.java(测试代码参考DOM方式):


public class PullXMLTools {    /**     * @param inputStream 服务器取得的流     * @param encode 编码格式     * @return     * @throws Exception      */    public static List<Person> parseXML(InputStream inputStream,String encode) throws Exception{        List<Person> list=null;        Person person=null;        //创建一个解析器工厂        XmlPullParserFactory factory=XmlPullParserFactory.newInstance();        //获得xml解析类的引用        XmlPullParser parser =factory.newPullParser();        parser.setInput(inputStream, encode);        //获得事件的类型        int eventType=parser.getEventType();        while(eventType!=XmlPullParser.END_DOCUMENT){            switch (eventType) {            case XmlPullParser.START_DOCUMENT:                list=new ArrayList<Person>();//新建一个list存储对象                break;            case XmlPullParser.START_TAG:                if("person".equals(parser.getName())){                    person=new Person();                    person.setId(Integer.parseInt(parser.getAttributeValue(0)));//取出属性值                }else if("name".equals(parser.getName())){                    person.setName(parser.nextText());                }else if("age".equals(parser.getName())){                    person.setAge(Integer.parseInt(parser.nextText()));//                }                break;            case XmlPullParser.END_TAG:                if("person".equals(parser.getName())){                    list.add(person);                    person=null;                }                break;            }            eventType=parser.next();        }        return list;    }}

============================================================================================

跟xml解析一样,json也有很多可供选择的解析包,其中比较常用的有jackson、gson、org.json等(PS:据说阿里的fastjson也不错,可惜那个文档真心蛋疼)。Android一开始就自带了org.json的解析包,在Android 3.0开始又集成了google自己的gson解析包,即新增的android.util.JsonReader和android.util.JsonWriter类。由于目前Android 2.3等低版本仍然占有比较大的比重,从兼容性的角度考虑,目前开发中一般还是选择org.json或者导入gson等解析包

json的基本格式

这个轻量级的数据交换格式是基于JavaScript的一个子集,说白了就是js的对象和数组。json采用了独立于语言的文本格式,有两种基本数据结构:对象和数组(两者各种嵌套形成较复杂的json数据)。
Json Array放在中括号[]里面,如[a,c,d...],就跟我们熟悉的数组没本质区别。数组中的元素可以是string, number, false, true, null, Object对象甚至是array数组。

Json Object放在大括号{}里面,表示成键值对{key1:value1, key2:value2, key3:value3,....}。其中(在面向对象的语言里)key为对象的属性,value为对应的属性值。key只能是string类型的, 而value可以是string, number, false, true, null, Object对象甚至是array数组, 也就是说可以存在嵌套的情况。(有点类似map)

解析json数据首先需要知道解析的是json数组还是json对象!下面将简单介绍一下gson和org.json包的基本使用。解析json内容前建议先根据json的内容建立相应的存储或者表示结构,本文例子里面都将使用到一个Person实体类:

public class Person {    private String name;    private  int age;    public Person() {        super();    }    public Person(String name, int age) {        super();        this.name = name;        this.age = age;    }    @Override    public String toString() {        return "Person [name="   name   ", age="   age   "]";    } //注:这里省略相应的setter和getter方法}
在本文中还用到 一些YY出来的json数据内容:

private String jsonArray = "[{"name":"Jack","age":20}, {"name":"mike","age":23},"             " {"name":"mary","age":22}]";//待解析的json数组,数组元素是嵌套的json对象    private String jsonObject="{"name":"Object","age":30}";//待解析的json对象    private List<Person> persons=new ArrayList<Person>();//假定ArrayList里面的数据需要转换成json格式以供传输//同时在onCreate()里面把persons初始化为:    persons.add(new Person("你妹",11 ));    persons.add(new Person("你弟",23 ));    persons.add(new Person("二货",33 ));

使用gson解析包

要想使用gson解析包必须首先下载并导入解析包,目前我在官网上看到的最新版本是gson-2.2.4.jar。gson里面通常可以采用两种方式来解析一个json格式数据:第一种方式就是采用JsonReader 逐字符解析json,利用beginArray()和endArray()方法来标志整个数组的开始和结束,解析json对象时采用类似的beginObject()和endObject()方法来标记开头和结尾。下面的第一种解析json数组的方法基本是**跟Android 3.0以后自带的android.util.JsonReader里面的解析方式类似**:

剩下的东西,还是去原链接看吧
原链接






0 0
原创粉丝点击