序:本文的读者对象可以是第一次接触Json数据并且想用Gson来简单实现Json数据的解析(Json数据可以转化成对象,对象亦可转化成Json数据)的新手,也可以是已有工作经验并不吝赐教的前辈。如果你是苦苦寻找更好地技术,正如本文标题所言,这篇文章可能不适合你。希望本篇能为新手们带来“众里寻他千百度,蓦然回首,那人却在灯火阑珊处”的发现,也能为有经验的前辈们带来那时年少的感觉。衷心希望你是耐心地愉快地读完本文!
0 偶遇JSON
{
“flag”:”00”,
“message”:”传感器”,
“property“:{“voltage”:”10V”,
“current”:”5A”},
“sensors”:[{“Date”:”time”,
”id”:”1527”}],
}
在这里还可见到更多的他:
http://www.tlink.io/web/developer-documentation-all.htm?type=1#api_1
1 认识JSON格式
JSON数据本质上是一种字符串,不过这个字符串有其特定的格式,一种分层形式的格式。最基本(最内层)的格式是键值对模型(如果不明白的话可以看看本文后面的附1,也可以在网上搜索相关内容,不过即使现在不清楚也不用着急,这不影响你理解JSON的数据形式),只是键需要被双引号包围,如:”Name0”:”lixiaobing0”,其中Name0为键,lixiaobing0为值,键和值都是自己定义的。这就是基本形式,为了下面的叙述的方便,以自己定义的符号base-type来代替”Name0”:”lixiaobing0”这个基本形式,这种代替是为了更方便地了解到JSON数据的全貌。于是细心的我们会看到,一个JSON数据里可以不止一个基本形式,可以有许多个,不过这些个基本形式之间要以逗号(,)分隔的,比如:base-type,base-type,┅。
如果将视野放得开阔点就会看到,这些基本形式可以被花括符{}或者中括号[]包围,如:{base-type}或者[base-type]。当然也可以被{}和[]同时包围,如:[{base-type}],但同时也要注意到,[{base-type}]形式里也可以有多个{base-type}形式,这些个{base type}形式之间以逗号(,)分隔,如:[{base-type},{base-type},{base type},┅],这和一个JSON数据里有多个基本形式是一样的。
通常,我们称被{}包围的数据为一个对象,被[]包围的数据我们成为数组,有一点要明白,不同对象的键都是一样的,不同的只是值,正如不同的人有不同性格爱好以及身高体重罢了。好了,我们跳出符号[]的限制,来到[]的外边看看,我们又会惊奇的发现这样的形式,”my_Array”:[{base-type},{base-type},{base type},┅],和这样的形式,”Object”:{base-type,base-type,┅},确实挺有意思,细细一看这不正和基本形式保持了一致吗。于是,用符号Array[]来代替”my_Array”:[{base-type},{base-type},{base-type},┅],用符号Object{}来代替”Object”:{base-type,base-type,┅}后,我们就看到了最外层的情况是这样的{ Object{},Array[],base-type}。
最外层的{}符号不能少,并且符号{} 里的Array[]、base-type和Object{}的数量都是任意的,可以为零,也可很多,也没什么顺序,更重要的是,Array[]和Object{}可以相互融合,做到你中有我,我中有你,即:Array[Object{}],Object{Array[]},这也被称为嵌套,嵌套可以多层,就像你的镜里有我的镜,我的镜里有你,镜里的还是镜,如此反复映射,不过嵌套多少层,映射多少次,当然这些都要视具体情况而定。注意到了吗,视具体情况而定,毕竟数据要用在某个场合里,至于如何用JSON数据这个问题将在后面JSON数据解析的部分讲解,这里还得举举JSON数据格式的例子,让我们具体感受一下JSON的魅力。
我会从简单到复杂,从单层到多层的顺序来举例子,因为这样也是符合人接受新事物的顺序。这些例子我是站在最基本形式的角度来阐述的,你也可以把自己当做最基本的形式,这样就可以经历一次有趣的旅程了。
1.1 最简洁的JSON数据(我也称为孤单的基本形式)
{”Name0”:”lixiaobing0”}
1.2 不再孤单的基本形式
{
”Name0”:”lixiaobing0”
”Name1”:”lixiaobing1”,
”Name2”:”lixiaobing2”,
... ...
}
1.3 从未见过的新伙伴age_Array
{
”age_Array”:[{”Age0”:”beautiful_24”}],
”Name0”:”lixiaobing0”
”Name1”:”lixiaobing1”,
”Name2”:”lixiaobing2”,
... ...
}
1.4 新伙伴不止秀一面
{
”age_Array”:[{”Age0”:”beautiful_24”,
”Age1”:”terrible_24”,
”Age2”:”wonderful_24”,
... ...}],
”Name0”:”lixiaobing0”
”Name1”:”lixiaobing1”,
”Name2”:”lixiaobing2”,
... ...
}
1.5 好多的新伙伴哇
{
”age_Array”:[{”Age0”:”beautiful_24”,
”Age1”:”terrible_24”,
”Age2”:”wonderful_24”,
... ...
},
{”Age0”:”beautiful_23”,
”Age1”:”terrible_23”,
”Age2”:”wonderful_23”,
... ...
},
... ...],
”Name0”:”lixiaobing0”
”Name1”:”lixiaobing1”,
”Name2”:”lixiaobing2”,
... ...
}
1.6 基本形式商量着结盟了
{
”age_Array”:[{”Age0”:”beautiful_24”,
”Age1”:”terrible_24”,
”Age2”:”wonderful_24”,
... ...},
{”Age0”:”beautiful_23”,
”Age1”:”terrible_23”,
”Age2”:”wonderful_23”,
... ...},
... ...],
”Name0”:{”Name00”:”lixiaobing00”
”Name01”:”lixiaobing01”,
”Name02”:”lixiaobing02”,
... ...},
”Name1”:{”Name13”:”lixiaobing13”
”Name14”:”lixiaobing14”,
”Name15”:”lixiaobing15”,
... ...},
... ...
}
1.7 原来新伙伴深藏不露
{
”age_Array”:[{”Hide_age_Array”:[{
”HeepAge0”:”H_beautiful_24”,
”HeepAge1”:”H_terrible_24”,
... ...},
{”HeepAge0”:”H_beautiful_23”,
”HeepAge1”:”H_terrible_23”,
... ...},
... ...],
... ...},
{”Age0”:”beautiful_24”,
”Age1”:”terrible_24”,
”Age2”:”wonderful_24”,
... ...},
{”Age0”:”beautiful_23”,
”Age1”:”terrible_23”,
”Age2”:”wonderful_23”,
... ...},
... ...],
”Name0”:{”Name00”:”lixiaobing00”
”Name01”:”lixiaobing01”,
”Name02”:”lixiaobing02”,
... ...},
”Name1”:{”Name13”:”lixiaobing13”
”Name14”:”lixiaobing14”,
”Name15”:”lixiaobing15”,
... ...},
... ...
}
1.8 我们都拿着一把镜子一起玩耍
{
”age_Array”:[{”Hide_age_Array”:[{”HeepAge0”:”H_beautiful_24”,
”HeepAge1”:”H_terrible_24”,
... ...},
HeepAge0”:”H_beautiful_23”,
”HeepAge1”:”H_terrible_23”,
... ...},
... ...],
... ...},
{”Age0”:”beautiful_24”,
”Age1”:”terrible_24”,
”Age2”:”wonderful_24”,
... ...},
{”Age0”:”beautiful_23”,
”Age1”:”terrible_23”,
”Age2”:”wonderful_23”,
... ...},
... ...],
”Name0”:{”Name00”:[{”Name_Age00”:”lixiaobing00_24”,
”Name_Age01”:”lixiaobing01_24”,
.. ...},
{”Name_Age00”:”lixiaobing00_23”,
”Name_Age01”:”lixiaobing01_23”,
... ...},
... ...],
”Name01”:”lixiaobing01”,
”Name02”:”lixiaobing02”,
... ...},
”Name1”:{”Name13”:[{”Name_Age10”:”lixiaobing10_24”,
”Name_Age11”:”lixiaobing11_24”,
... ...},
{”Name_Age10”:”lixiaobing10_23”,
”Name_Age11”:”lixiaobing11_23”,
... ...},
... ...],
”Name14”:”lixiaobing14”,
”Name15”:”lixiaobing15”,
... ...},
... ...
}
注:这里再说明一下,JSON中值(value)存在的数据类型可以是数字型(整数或浮点数),字符串型,逻辑值型(true/false),数组,对象,或者为空。
2 GSON解析JSON数据
本文采用JAVA语言编程,使用Google的GSON类库里的方法,在eclipse集成环境里来析JSON数据,当然需要再建的的项目里导入GSON包,至于如何导入可参考百度里的经验。这里解析数据正如我们吃西瓜一样,一刀一刀地去切或是一勺一勺地取,只要方法对了,不管怎样,西瓜会越来越少(数据会越来越简单),直到最后整个西瓜都到我们的肚子里去了。既然是使用类库的方法就解析了JSON数据,那我们要干些什么事呢?我们干的事自然是在解析数据之前我们得确立规则,即确立JSON数据对应着怎样的类,这就好比确立怎么切怎么或取西瓜。不废话了,开始来解析数据咯!
2.1 建立与JSON数据对应的类
规则:基本形式base-type定义成类中的字段。
形式Object{}定义成一个类Object,形式Array[{}]里的对象{}定义成一个类Array。
形式Object{Array[]}定义为有个字段为数组或列表的类Object。
整个{ Object{},Array[],base-type}定义成一个主类Example。
注:类中字段的名字要和JSON数据键的写法保持一致。
目的 : 要使构建的类之间的组织结构与JSON数据的结构保持一致。
举例:
还是用最初偶遇到的那个JSON举例吧,只是改动了一下,在property里嵌套了个数组,增加了结构的复杂性,这样可以具有一般的参考性。
{ “flag”:”00”, “message”:”传感器”, “property”:{“electricity”:[{ “voltage”:”10V”, “current”:”5A”}], “temp”:”temperature”}, “sensors”:[{“Date”:”time”, “id”:”9527”}] }
这里,从里向外依次定义类,首先定义类Electricity,Electricity类有两个字符串型的字段voltage和current。定义类Property,这个类有一个字符串型String的字段temp和要装载Electricity类的列表electricity。然后接着定义类Sensor,也有两个字符串型的字段Date和id,最后整个JSON数据建立一个类,取名为Example,包含字符串型String的字段flag和message,以及Property类型的property字段和装载Sensors类型对象的列表sensors。类定义时,要特别注意Json数据中的键名和类中的字段名的书写要对应,不然在解析的时候会报异常。好了,具体的类定义如下所示:
####2.1.1 类Electricity:public class Electricity { private String voltage; private String current; public Electricity() { super(); } public Electricity(String voltage, String current) { super(); this.voltage = voltage; this.current = current; } public String getVoltage() { return voltage; } public void setVoltage(String voltage) { this.voltage = voltage; } public String getCurrent() { return current; } public void setCurrent(String current) { this.current = current; } @Override public String toString() { return "Electricity [voltage=" + voltage + ", current=" + current+"]"; } }####2.1.2 类Property
public class Property { private List <Electricity> electricity; private String temp; public Property() { super(); } public Property(List<Electricity> electricity, String temp) { super(); this.electricity = electricity; this.temp = temp; } public List<Electricity> getElectricity() { return electricity; } public void setElectricity(List<Electricity> electricity) { this.electricity = electricity; } public String getTemp() { return temp; } public void setTemp(String temp) { this.temp = temp; } @Override public String toString() { return "Property [electricity=" + electricity + " temp="+temp+"]"; } }####2.1.3 类Sensor
public class Sensor { private String Date; private String id; public Sensor() { super(); } public Sensor(String date, String id) { super(); Date = date; this.id = id; } public String getDate() { return Date; } public void setDate(String date) { Date = date; } public String getId() { return id; } public void setId(String id) { this.id = id; } @Override public String toString() { return "Sensor [Date=" + Date + ", id=" + id + "]"; } }####2.1.4 类Example
public class Example { private String flag; private String message; private Property property; private List<Sensor> sensors; public Example() { super(); } public Example(String flag, String message, Property property, List<Sensor> sensors) { super(); this.flag = flag; this.message = message; this.property = property; this.sensors = sensors; } public String getFlag() { return flag; } public void setFlag(String flag) { this.flag = flag; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public Property getProperty() { return property; } public void setProperty(Property property) { this.property = property; } public List<Sensor> getSensors() { return sensors; } public void setSensors(List<Sensor> sensors) { this.sensors = sensors; } @Override public String toString() { return "Example [flag=" + flag + ", message=" + message + ", property=" + property + ", sensors=" + sensors + "]"; } }
好了,该定义的类都定义完了,接下来就是第二步了,定义运行程序的主类Example_Test。
2.2 JSON数据与对象的转化
2.2.1 运行程序的主类Example_Test:
public class ExampleTest { public static void main(String[] args) { String json = "{\"flag\":\"00\",\"message\":\"传感器\"," +"\"property\" {\"electricity\":[{\"voltage\":\"10V\",\"current\":\"5A\" }],\"temp\":\"temperature\"}," +"\"sensors\":[{\"Date\":\"time\",\"id\":\"9527\"}]}"; Gson gson = new Gson(); //创建Gson类的对象 Example example = new Example(); //创建与json数据对应的类的对象 example = gson.fromJson(json, Example.class); //将json数据解析成对象 System.out.println(example.getFlag()); System.out.println(example.getMessage()); System.out.println(example.getProperty()); System.out.println(example.getSensors().toString()); String json1 = gson.toJson(example); //将对象解析成Json数据 System.out.println(json1); } }
注意:与JSON数据相对应的类Electricity、Property、Sensor、Example建议放在同一个包里,如果没放在同一个包里,应在Example那个类里导入相应的类Electricity、Property、Sensor,导入的形式为:import another. Electricity,这里another为存放类Electricity的包。另外,类Electricity、Property、Sensor也可以作为类Example的内部类。这里使用简单形式的内部类就可以了,至于有关内部类的知识,在这里就不详谈了,读者可参考Java入门书籍。
2.2.2 程序运行结果:
00
传感器
Property [electricity=[Electricity [voltage=10V, current=5A]] temp=temperature]
[Sensor [Date=time, id=9527]]
{"flag":"00","message":"传感器","property":{"electricity":[{"voltage":"10V","current":"5A"}],"temp":"temperature"},"sensors":[{"Date":"time","id":"9527"}]}
运行结果中,前四行是JSON数据转化为对象后通过get()方法获得的字段,最后一行是把对象转化为JSON字符串,和开始的那个JSON数据字符串一样,也说明了GSON已成功解析了这个JSON字符串。
本运行程序的主类Example_Test还有值得完善的地方,比如如果JSON数据是非常多的时候就不能在程序里直接写JSON数据,需要使用文件流来读取。还有一个值得完善的地方是考虑异常的情况,常见的异常如:JSON数据的格式错误,JSON数据的键名和对象的字段名不相匹配等等。JSON数据的解析方法不止使用GSON,还有JSONObject和JSONArray类,这个同样需要导入相应的包,当然你可以去试试。
通常的情况下,人们不会通俗的说将JSON数据转化为对象这一过程,或者将对象转化为JSON数据,人们更多提到的是序列化和反序列化(如果暂时不清楚的话也没关系,因为在多次打交道后就会慢慢理解了,也可参考http://kb.cnblogs.com/page/515982/)。在这里,如果不要求严格地概念的话,也可通俗地把对象转化为JSON数据这一过程叫做序列化,把JSON数据转化为对象叫做反序列化。
当你看到这里的时候是不是认识到使用Gson类来解析JSON数据没什么难度了呢,就两步而已,第一步先定义与GSON数据格式对应的类,第二步在主类中使用gson.fromJson()和gson.toJson()方法就可以实现JSON数据和对象之间的转换了。最后再说明一下,本文的源码的下载地址可在本文尾部的附2里找到,以供参考。
3 终点与起点
到了这次旅程的终点了,也许现在你已是兴趣盎然,打算迈进新的旅途,这里我提供了有关JSON数据及GSON的一些驿站,希望对你有所帮助:
http://jsonapi.org.cn/format/
http://www.json.org/json-zh.html
https://github.com/google/gson
http://www.w3school.com.cn/json/json_intro.asp
http://baike.baidu.com/link?url=TOZY8cSwFBQc0011WK7ccHd6umlhXGTqo6YKaLKGVaZBEBI uSjVCn3Sg8D_tEQcg39ZMsiljA2Z095H2GzJ4_
http://www.cnblogs.com/tianzhijiexian/p/4246497.html
附1 键值对模型简要:键盘上的一个键对应着一个符号,每个人都对应着一个名,每一个公司的名字都对应着一个图标(Logo),每一把钥匙都对应着一把锁等等,像这之类的数据形式被称为键值对Key/Value,键值对模型本质上是一种一一映射的关系模型。在JSON数据中,键值对模型的格式为 “Key”:Value,其中值取值可以是数字(整数/浮点数)、字符串、逻辑值(true/false)、数组、对象或者空null。 键(Key)和值(Value)的书写格式可参考程序的命名规则。
附2 本文源码地址1:http://download.youkuaiyun.com/detail/huangdoudecsdn/9466453,名称叫做Gson解析JSON数据的入门级源码。
本文源码地址2:http://pan.baidu.com/s/1eRefHBG , 这是一个名称为GsonExplainJson的压缩包。