JSON解析以及GSON簡明使用

json頭圖

我的博客:http://southtree.cn

何為JSON

JSON為JavaScript Object Notation的簡稱,是一種用于輕量級的數(shù)據(jù)交換語言,是用了存儲和交換文本信息的語法。盡管JSON是JavaScript的一個子集,但JSON是獨立于語言的文本格式,目前很多主流的編程語言都支持JSON。
說到JSON就不得不提到xml,與XML想比,JSON占用更小、速度更快,更易解析。JSON不可用于配置文件,僅僅作為傳輸信息來使用。

JSON基本語法規(guī)則

下面是幾個JSON中的基本也是最重要的概念,JSON也就這幾個概念

對象

一個對象一個對象以{開始,并以}結(jié)束。

數(shù)組

JSON另外一個常用的概念是數(shù)組,在鍵值對中的值或者對象中有時候并不可能是一個簡單的值,有時候則可能是數(shù)組。數(shù)組或有序列表,使用[,]來表示。

鍵值對

在對象中通常包含不止一個"鍵-值"對。鍵值對以{"名稱":"值"}的形式書寫,如果是多對鍵值對則用分隔。鍵值對的一個名稱是一個字符串; 一個值可以是一個字符串,一個數(shù)值,一個對象,一個布爾值,一個有序列表,或者一個null值。


JSON基本解析實例

一個簡單的小例子

這里是我從wiki中直接拿過來的一個例子,我覺得非常的好,就拿來直接用。這是一個名為 Jhon Smith的“電話簿”。我們一行行來看。

{   //①最外層是一個JSON對象,{}中間的為這個對象的內(nèi)容。
     "firstName": "John",  //②一個鍵值對,名稱為firstName,值為John,用逗號隔開鍵值對
     "lastName": "Smith",  //同②,略
     "sex": "male",        //同②,略
     "age": 25,            //同②,略
     "address":  //③一個鍵值對,名稱為address,值為一JSON對象
     {
         "streetAddress": "21 2nd Street",  //同②,略
         "city": "New York",                //同②,略
         "state": "NY",                     //同②,略
         "postalCode": "10021"              //同②,略
     },
     "phoneNumber"://④一個鍵值對,名稱為phoneNumber,但是值是JSON數(shù)組。
     [  //⑤這里是數(shù)組的開始,數(shù)組的大小為2,內(nèi)容為2個對象,數(shù)組元素之間使用,隔開。
         {  //⑥數(shù)組中第一個元素,為一JSON對象
           "type": "home",
           "number": "212 555-1234"
         },
         {
           "type": "fax",
           "number": "646 555-4567"
         }
     ]
 }

既然文章叫做JSON解析,上面都是論述,總得有個具體的解析吧,那么下面我使用JAVA來常識解析上面的小例子。

//JAVA中json包的引用我就不說了。
String json=response.body().string;  //假設(shè)從服務(wù)拿出來的json字符串,就是上面的內(nèi)容
JSONObject personObj = new JSONObject(json); //①創(chuàng)建一個名為person的JSONObject類型。

//②下面分別取出 最外層JSONObject包裹的firstName、lastName等字符串
System.out.println(personObj.getString("firstName"));
System.out.println(personObj.getString("lastName"));
System.out.println(personObj.getString("sex"));
System.out.println(personObj.getInt("age"));

//③下面是取出 最外層JSONObject包裹的名稱為address的JSONObject
JSONObject addressObj = personObj.getJSONObject("address");

//④下面是取出 addressObject中的streetAddress等對應(yīng)的字符串
System.out.println(addressObj.getString("streetAddress");
System.out.println(addressObj.getString("city");
System.out.println(addressObj.getString("state");
System.out.println(addressObj.getString("postalCode");
//⑤下面是取出 最外層JSONObject包裹的名稱為phoneNumber的JSONArray
JSONArray phoneNumberArray = personObj.getJSONArry("phoneNumber");

//⑥下面是利用循環(huán) 讀取phoneNumberArray 中的信息
for(int i = 0;i < phoneNumberArray.lenth(); i++){
    JSONObject tempObj = phoneNumberArray.getJSONObject(i);
    System.ouy.println(tempObj.getString("type"));
    System.ouy.println(tempObj.getString("number"));
    
}

實例

和風(fēng)天氣api返回json結(jié)果

這里的實例引用了和風(fēng)天氣api的例子,和風(fēng)天氣的是我做課程作業(yè)需要使用到的,也是我接觸的第一個實際開發(fā)過程中使用的例子。
這是我直接從服務(wù)器拿回來的json的數(shù)據(jù),我第一次看,感覺十分的復(fù)雜 - -。

{"HeWeather5":[{"aqi":{"city":{"aqi":"66","pm10":"82","pm25":"38","qlty":"良"}},"basic":{"city":"常熟","cnty":"中國","id":"CN101190402","lat":"31.658156","lon":"120.74852","update":{"loc":"2017-04-04 16:51","utc":"2017-04-04 08:51"}},"daily_forecast":[{"astro":{"mr":"11:41","ms":"00:51","sr":"05:42","ss":"18:19"},"cond":{"code_d":"104","code_n":"305","txt_d":"陰","txt_n":"小雨"},"date":"2017-04-04","hum":"61","pcpn":"0.0","pop":"0","pres":"1020","tmp":{"max":"20","min":"15"},"uv":"7","vis":"16","wind":{"deg":"141","dir":"東南風(fēng)","sc":"微風(fēng)","spd":"5"}},{"astro":{"mr":"12:41","ms":"01:45","sr":"05:41","ss":"18:20"},"cond":{"code_d":"104","code_n":"305","txt_d":"陰","txt_n":"小雨"},"date":"2017-04-05","hum":"75","pcpn":"2.3","pop":"71","pres":"1015","tmp":{"max":"20","min":"16"},"uv":"8","vis":"14","wind":{"deg":"145","dir":"南風(fēng)","sc":"微風(fēng)","spd":"3"}},{"astro":{"mr":"13:41","ms":"02:32","sr":"05:40","ss":"18:20"},"cond":{"code_d":"306","code_n":"305","txt_d":"中雨","txt_n":"小雨"},"date":"2017-04-06","hum":"81","pcpn":"7.5","pop":"100","pres":"1010","tmp":{"max":"22","min":"13"},"uv":"5","vis":"10","wind":{"deg":"189","dir":"東北風(fēng)","sc":"微風(fēng)","spd":"7"}}],"hourly_forecast":[{"cond":{"code":"100","txt":"晴"},"date":"2017-04-04 19:00","hum":"62","pop":"0","pres":"1019","tmp":"17","wind":{"deg":"142","dir":"東南風(fēng)","sc":"3-4","spd":"18"}},{"cond":{"code":"103","txt":"晴間多云"},"date":"2017-04-04 22:00","hum":"72","pop":"0","pres":"1018","tmp":"16","wind":{"deg":"148","dir":"東南風(fēng)","sc":"3-4","spd":"18"}}],"now":{"cond":{"code":"104","txt":"陰"},"fl":"18","hum":"49","pcpn":"0","pres":"1019","tmp":"19","vis":"8","wind":{"deg":"144","dir":"東南風(fēng)","sc":"3-4","spd":"16"}},"status":"ok","suggestion":{"air":{"brf":"中","txt":"氣象條件對空氣污染物稀釋、擴散和清除無明顯影響,易感人群應(yīng)適當(dāng)減少室外活動時間。"},"comf":{"brf":"舒適","txt":"白天不太熱也不太冷,風(fēng)力不大,相信您在這樣的天氣條件下,應(yīng)會感到比較清爽和舒適。"},"cw":{"brf":"不宜","txt":"不宜洗車,未來24小時內(nèi)有雨,如果在此期間洗車,雨水和路上的泥水可能會再次弄臟您的愛車。"},"drsg":{"brf":"較舒適","txt":"建議著薄外套、開衫牛仔衫褲等服裝。年老體弱者應(yīng)適當(dāng)添加衣物,宜著夾克衫、薄毛衣等。"},"flu":{"brf":"易發(fā)","txt":"相對于今天將會出現(xiàn)大幅度降溫,空氣濕度較大,易發(fā)生感冒,請注意適當(dāng)增加衣服。"},"sport":{"brf":"較適宜","txt":"陰天,較適宜進行各種戶內(nèi)外運動。"},"trav":{"brf":"適宜","txt":"天氣較好,風(fēng)稍大,但溫度適宜,總體來說還是好天氣。這樣的天氣適宜旅游,您可以盡情享受大自然的風(fēng)光。"},"uv":{"brf":"最弱","txt":"屬弱紫外線輻射天氣,無需特別防護。若長期在戶外,建議涂擦SPF在8-12之間的防曬護膚品。"}}}]}

使用工具格式化

當(dāng)我使用工具將這串字符格式化后更加清晰可讀了。

JSON格式化后

從圖中可以看出清楚的看出整個和風(fēng)天氣json的結(jié)構(gòu),左邊是格式化后代碼,右邊是一個樹狀圖結(jié)構(gòu)。
首先在整個結(jié)構(gòu)的最外層是一個鍵值對,名稱為HeWeather5(因為是x5版本),值為一JSON數(shù)組類型且這個數(shù)組僅含有一個JSONObject類型的元素。
接著,在這個JSONObject下面有7個鍵值對,名稱分別是"aqi"(城市空氣質(zhì)量狀況),"basic"(城市基礎(chǔ)信息),"daily_forecast"(三天的日預(yù)報),"hourly_forecast"(每小時的預(yù)報),"now"(現(xiàn)在的天氣情況),"status"(返回消息的狀態(tài)),"suggestion"(建議信息)。他們對應(yīng)著或是幾組JSONObject或是JSONArray信息的值,甚至再接著嵌套多次信息。那么我們只要根據(jù)形勢進行相應(yīng)的展開就好了。
下面,我將做示范。
別想了!這個嵌套我要寫老久,我好菜。明天試試

//占坑

拓展

引子

那么,當(dāng)處理這些json嵌套的時候,首先要進行對數(shù)據(jù)的建模,然后解開這些嵌套,然后把相應(yīng)的值給填進去。但當(dāng)我們遇到一個更復(fù)雜的json時,這個工作就很是繁瑣,所以下面就引入了很是方便的辦法。

GSON使用

簡介

Gson(又稱Google Gson)是Google公司發(fā)布的一個開放源代碼的Java庫,主要用途為序列化Java對象為JSON字符串,或反序列化JSON字符串成Java對象。
下面是我在Android 中使用GSON根據(jù)上述的和風(fēng)天氣的例子,進行解析的過程。

導(dǎo)包

首先使用GSON需要導(dǎo)包,因為使用Android Studio的原因,只需要在app的gradle中的dependencies依賴中添加:

compile 'com.google.code.gson:gson:2.7'

創(chuàng)建POJO類

接著根據(jù)實際,需要創(chuàng)建POJO類,根據(jù)分析后的json代碼,當(dāng)我們把第一層解開后,其實是一個JSONObject嵌套6個JSONObject和一個鍵值對的情況。那么我們根據(jù)實際需要(用到什么取什么或者是全?。×薬qi,basic等對應(yīng)的5幾個JSONObject類。下面單獨拿出來幾個進行講解。

例子①

這邊是經(jīng)過格式化和tree化的aqi相關(guān)的json原碼,注意兩個紅框處。


aqi
//①Aqi.java
public class Aqi {
    public AqiCity city;
    public class AqiCity{
        public String aqi;
        public String pm25;
    }
}

在上述代碼中,創(chuàng)建一個POJO類,其中僅有一個,名為city的內(nèi)部類AqiCity成員變量,其中內(nèi)部類AqiCity有兩個公有變量:aqi和pm25。

總結(jié)一下,每當(dāng)JSONObject的內(nèi)部有一個JSONObject,就需要在POJO類內(nèi)部創(chuàng)建一個內(nèi)部類并添加一個相應(yīng)成員變量,該成員變量名應(yīng)該和json鍵值對的鍵名相一致。

下面這個圖可以粗略的看出對應(yīng)關(guān)系。


json與pojo類對應(yīng)關(guān)系

例子②

這邊是經(jīng)過格式化和tree化的basic相關(guān)的json原碼,注意兩個紅框處。


basic
//②Basic.java
public class Basic {
    @SerializedName("city")
    public String cityName;
    
    @SerializedName("id")
    public String weatherId;
    
    public Update update;
    public class Update{
        @SerializedName("loc")
        public String UpdateTime;
    }
}

在例子①中POJO類的變量名稱和json的鍵值對的名稱都是一樣的,那么在上面的例子中,并不對應(yīng),那么這時就需要使用注解的方式:添加一個@SerializedName("city")進行注解。
但是如果我如果是不同服務(wù)器發(fā)出的json,僅僅只是鍵名不同,那么我的POJO類又該怎么處理呢?那么將注解這樣寫:

@SerializedName(value = "cityName", alternate = {"cityname", "city_name"})

總之就是,如果 POJO對象/變量 想要和json中不一致,就需要注解。

例子③

這邊是經(jīng)過格式化的json原碼,注意兩個紅框處。


weather
//③Weather.java
public class Weather {
    public String status;
    public Basic basic;
    public Aqi aqi;
    public Now now;
    public Suggestion suggestion;
    @SerializedName("daily_forecast")
    public List<Forecast> forecastList;
}

Weather.java是將這6個JSONObject和1個鍵值對嵌套在一起的POJO類,但是我們在嵌套的時候,又會遇到一個問題:daily_forecast對應(yīng)的是一個JSONArray,JSONArray的每一個元素又是一個JSONObject這時候應(yīng)該怎么做呢?
根據(jù)上面的代碼,可以看出這里使用了List<>,使用java的list的泛型來構(gòu)造。即,JSONArray型變量需要使用List創(chuàng)建并根據(jù)元素類型,選擇是否要用泛型

總結(jié)三點:

  1. 每當(dāng)JSONObject的內(nèi)部有一個JSONObject,就需要在POJO類內(nèi)部創(chuàng)建一個內(nèi)部類并添加一個相應(yīng)成員變量,該成員變量名應(yīng)該和json鍵值對的鍵名相一致。
  2. 如果 POJO對象/變量 想要和json中不一致,就需要注解。
  3. JSONArray型變量需要使用List創(chuàng)建并根據(jù)元素類型,選擇是否要用泛型。

JSON轉(zhuǎn)化為GSON

最后,只需要將獲取的json轉(zhuǎn)化為gson就可以了,這里用到了gson的fromJson方法。

public static Weather handleWeatherResponse(String response){
    try{
    //因為最外面仍有一個JSONObject所以,只需要手動把它解開接行了
    JSONObject jsonObject = new JSONObject(response);
    JSONArray jsonArray = jsonObject.getJSONArray("HeWeather5");
    String weatherContent = jsonArray.getJSONObject(0).toString();
    //fromJson方法需要包含兩個參數(shù),第一個為json代碼,第二個為創(chuàng)建的POJO類
    return new Gson().fromJson(weatherContent,Weather.class);
    }catch (Exception e){
        e.printStackTrace();
     }
        return null;
    }

如果正常,這個函數(shù)就會返回一個Weather類型的值,此時我們需要的參數(shù)都包含在里面了!

One More Thing : Gsonformat

  1. 重復(fù)大量的POJO創(chuàng)建工作是一件很傷腦經(jīng)的事情,這里我們引入一個Android Studio的插件:Gsonformat,使用它就可以很方便的構(gòu)造模型。
    這里不做過多敘述了,點擊這個鏈接查看Gsonformat的配置以及使用。
  2. 本篇博文參考你真的會用Gson嗎?Gson使用指南(一) - 簡書。是一篇非常好的參考gson使用指南。
  3. 推薦幾款實用的Android Studio 插件 - 簡書
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容