前三篇博客分別介紹了xml的三種解析方法,分別是SAX,DOM,PULL解析XML,興趣的朋友能夠去看一下這【XML解析(一)】SAX解析XML,【XML解析(二)】DOM解析XML,【XML解析(三)】PULL解析XML三篇文章學習一下XML解析。咱們知道客戶端請求服務器,服務器給咱們返回的數據一般不僅是xml,還能夠是json,html,固然json和xml是用的最多的了,下篇文章將會向你們解析如何解析html數據,這篇文章先向你們介紹如何解析服務器給咱們返回的json數據。javascript
JSON是JavaScript Object Notation的簡稱,起源於js(javascript)它是一種輕量級的數據交換格式,JSON不只在js中普遍使用,同時還在其餘領域獲得普遍使用,如c,c++,java,Php,swift等等,成爲了一種通用的理想數據交換格式,它有兩種數據結構,分別是對象,數組,它形式上有花括號{}和中括號[]嵌套,{}中的是表明對象,[]中的爲數組,即對象中有數組,數組中又有對象,並且以及鍵/值對出現。html
JSON語法:
json是javascript對象表示語法的子集java
JSON的值:android
json和xml比較:c++
大概瞭解了JSON,下面將介紹在Android中經過採用android內置的org.json包,android 3.0 新出的JsonReader,google提供的gson解析json這三種經常使用的方式解析json。json
要學習怎麼解析json,咋們先要獲得json數據,獲得json數據方式有不少種,好比:webservice接口api,本身寫個服務器端,或者本身在代碼中寫一個json格式的字符串。下面咱們將經過金山詞霸開放平臺爲咱們提供的每日一句的api接口演示三種解析json的方法。swift
金山詞霸每日一句api接口:http://open.iciba.com/dsapiapi
要解析json,咱們得先知道要解析json的格式及內容,咱們先用瀏覽器訪問每日有一句api接口看看返回的數據。數組
訪問結果:
{"sid":"1683","tts":"http:\/\/news.iciba.com\/admin\/tts\/2015-12-07-day.mp3","content":"You aspire to do great things? Begin with little ones.\t","note":"\u60f3\u6210\u5c31\u5927\u4e8b\uff0c\u5c31\u8981\u4ece\u5c0f\u4e8b\u5f00\u59cb\u3002\uff08Augustine of Hippo\uff09","love":"2437","translation":"\u8bcd\u9738\u5c0f\u7f16\uff1a\u62e5\u6709\u597d\u5fc3\u60c5\u7684\u6700\u4f73\u65b9\u5f0f\u5c31\u662f\u201c\u5e72\u6b63\u4e8b\u201d\u3002\u5b66\u4f1a\u4e86\u89c4\u5b9a\u7684\u5355\u8bcd\uff0c\u8bfb\u5b8c\u4e86\u5fc5\u8bfb\u7684\u4e66\uff0c\u6536\u5c3e\u4e86\u5de5\u4f5c\uff0c\u953b\u70bc\u6ca1\u6709\u5077\u61d2\u2026\u90a3\u4e48\u9047\u5230\u6001\u5ea6\u4e0d\u597d\u7684\u51fa\u79df\u53f8\u673a\uff0c\u591a\u6536\u94b1\u7684\u770b\u8f66\u5927\u5988\uff0c\u6392\u961f\u52a0\u585e\u7684\u65e0\u826f\u9752\u5e74\u4e5f\u4f1a\u4e00\u7b11\u7f6e\u4e4b\uff0c\u5fc3\u4e2d\u5145\u5b9e\uff0c\u624d\u6709\u5e95\u6c14\u5feb\u4e50\u3002\u3010\u5173\u6ce8\u8bcd\u9738\u5c0f\u59b9\u5fae\u4fe1\uff08\u5fae\u4fe1\u53f7\uff1aijinshanciba\uff09\uff0c\u6709\u60ca\u559c\u5466\uff01\u3011","picture":"http:\/\/cdn.iciba.com\/news\/word\/2015-12-07.jpg","picture2":"http:\/\/cdn.iciba.com\/news\/word\/big_2015-12-07b.jpg","caption":"\u8bcd\u9738\u6bcf\u65e5\u4e00\u53e5","dateline":"2015-12-07","s_pv":"6694","sp_pv":"121","tags":[{"id":"13","name":"\u540d\u4eba\u540d\u8a00"},{"id":"16","name":"\u6cbb\u6108\u7cfb"}],"fenxiang_img":"http:\/\/cdn.iciba.com\/web\/news\/longweibo\/imag\/2015-12-07.jpg"}
哎呀,這尼瑪!,這是什麼啊,簡直是沒法直視啊,還要解析?不過沒關係,咱們能夠對該json數據先格式化一下,市場上有不少json格式化工具及在線json格式工具等等,這裏我推薦一個工具,叫HiJson,點擊這裏下載:HiJson下載
HiJson的使用很是簡單,下面用一張圖說明一下HiJson的使用:
其中面板3顯示面板2選擇節點的鍵/值
將每日一句的json的數據格式化後的結果:
{ "caption": "詞霸每日一句", "content": "You aspire to do great things? Begin with little ones. ", "dateline": "2015-12-07", "fenxiang_img": "http://cdn.iciba.com/web/news/longweibo/imag/2015-12-07.jpg", "love": "2437", "note": "想成就大事,就要從小事開始。(Augustine of Hippo)", "picture": "http://cdn.iciba.com/news/word/2015-12-07.jpg", "picture2": "http://cdn.iciba.com/news/word/big_2015-12-07b.jpg", "s_pv": "6694", "sid": "1683", "sp_pv": "121", "tags": [ { "id": "13", "name": "名人名言" }, { "id": "16", "name": "治癒系" } ], "translation": "詞霸小編:擁有好心情的最佳方式就是「幹正事」。學會了規定的單詞,讀完了必讀的書,收尾了工做,鍛鍊沒有偷懶…那麼遇到態度很差的出租司機,多收錢的看車大媽,排隊加塞的無良青年也會付之一笑,心中充實,纔有底氣快樂。【關注詞霸小妹微信(微信號:ijinshanciba),有驚喜呦!】", "tts": "http://news.iciba.com/admin/tts/2015-12-07-day.mp3" }
能夠看到格式化後的數據結構很是清晰,這就是標準的json格式,有了json數據,下面咱們就用org.json包(無需導入),JsonReader,Gson解析該json數據。
打開eclipse(這裏只是演示一下解析json,就不用as(Android Studio)了)新建一個Android項目,爲了方便,這裏先將整個項目的目錄結構貼出來,整個項目的代碼將會在文章貼在文章末尾,方便下載。
目錄結構:
代碼編寫:
一、 寫一個工具類,JsonParseUtils.java,寫一個請求獲得json數據的方法
/** * 鏈接網絡請求數據,這裏使用HttpURLConnection */ public static String getJsonData() { URL url = null; String jsonData = ""; // 請求服務器返回的json字符串數據 InputStreamReader in = null; // 讀取的內容(輸入流) try { url = new URL("http://open.iciba.com/dsapi"); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); // 這一步會鏈接網絡獲得輸入流 in = new InputStreamReader(conn.getInputStream()); // 爲輸入建立BufferedReader BufferedReader br = new BufferedReader(in); String inputLine = null; while(((inputLine = br.readLine()) != null)){ jsonData += inputLine; } in.close(); // 關閉InputStreamReader // 斷開網絡鏈接 conn.disconnect(); } catch (Exception ex) { ex.printStackTrace(); } return jsonData; }
注意:HttpURLConnection默認是Get請求,若是要使用Post請求,須要對HttpURLConnection作一些配置,獲得數據後記得關閉流和斷開網絡連接。
不要忘了添加請求網絡的權限
<uses-permission android:name="android.permission.INTERNET"/>
二、解析JSON
/** * 經過org.json解析json * @param jsonStr json字符串 * @throws JSONException 格式不對,轉換異常 */ public static Sentence parseJsonByOrgJson(String jsonStr) throws JSONException{ // 使用該方法解析思路,遇到大括號用JsonObject,中括號用JsonArray // 第一個是大括號{} JSONObject jsonObj = new JSONObject(jsonStr); // 新建Sentence對象 Sentence sentence = new Sentence(); // 如下是無腦操做 String caption = jsonObj.getString("caption"); String content = jsonObj.getString("content"); String dateline = jsonObj.getString("dateline"); String fenxiang_img = jsonObj.getString("fenxiang_img"); String love = jsonObj.getString("love"); String note = jsonObj.getString("note"); String picture = jsonObj.getString("picture"); String picture2 = jsonObj.getString("picture2"); String s_pv = jsonObj.getString("s_pv"); String sp_pv = jsonObj.getString("sp_pv"); String translation = jsonObj.getString("translation"); String tts = jsonObj.getString("tts"); sentence.caption = caption; sentence.content = content; sentence.dateline = dateline; sentence.fenxiang_img = fenxiang_img; sentence.love = love; sentence.note = note; sentence.picture = picture; sentence.picture2 = picture2; sentence.s_pv = s_pv; sentence.sp_pv = sp_pv; sentence.translation = translation; sentence.tts = tts; // 解析關鍵字tags,它是一個JsonArray,遇到[] JSONArray jsonArray = jsonObj.getJSONArray("tags"); // 新建Tag集合 List<Sentence.Tag> tags = new ArrayList<Sentence.Tag>(); for(int i=0;i<jsonArray.length();i++){ Sentence.Tag tag = new Sentence.Tag(); // jsonArray裏的每一項都是JsonObject JSONObject jsonObject = jsonArray.getJSONObject(i); tag.id = jsonObject.getInt("id"); tag.name = jsonObject.getString("name"); tags.add(tag); } sentence.tags = tags; return sentence; }
使用這種方法解析JSON,看註釋,沒什麼好多的,總結一句話就是:遇到{}用JSONObject,遇到[]用JSONArray,這樣你就能夠說你精通org.json解析JSON了。
/** * Call requires API level 11 (current min is 8): new * android.util.JsonReader 經過org.json解析json * * @param jsonStr * json字符串 * @throws Exception */ @SuppressLint("NewApi") public static Sentence parseJsonByJsonReader(String jsonStr) throws Exception { // 新建Sentence Sentence sentence = new Sentence(); // 新建Tag集合 List<Sentence.Tag> tags = new ArrayList<Sentence.Tag>(); JsonReader reader = new JsonReader(new StringReader(jsonStr)); // 遇到{,開始解析對象 reader.beginObject(); while (reader.hasNext()) { String name = reader.nextName(); if ("caption".equals(name)) { sentence.caption = reader.nextString(); } if ("content".equals(name)) { sentence.content = reader.nextString(); } if ("dateline".equals(name)) { sentence.dateline = reader.nextString(); } if ("fenxiang_img".equals(name)) { sentence.fenxiang_img = reader.nextString(); } if ("love".equals(name)) { sentence.love = reader.nextString(); } if ("note".equals(name)) { sentence.note = reader.nextString(); } if ("picture".equals(name)) { sentence.picture = reader.nextString(); } if ("picture2".equals(name)) { sentence.picture2 = reader.nextString(); } if ("s_pv".equals(name)) { sentence.s_pv = reader.nextString(); } if ("sid".equals(name)) { sentence.sid = reader.nextString(); } if ("sp_pv".equals(name)) { sentence.sp_pv = reader.nextString(); } if ("translation".equals(name)) { sentence.translation = reader.nextString(); } if ("tts".equals(name)) { sentence.tts = reader.nextString(); } if ("tags".equals(name)) { // 遇到[,開始解析數組 reader.beginArray(); while (reader.hasNext()) { // 遇到{,開始解析對象 reader.beginObject(); Sentence.Tag tag = new Sentence.Tag(); if ("id".equals(reader.nextName())) { tag.id = reader.nextInt(); } if ("name".equals(reader.nextName())) { tag.name = reader.nextString(); } // 遇到},對象解析結束 reader.endObject(); tags.add(tag); } sentence.tags = tags; // 遇到],數組解析結束 reader.endArray(); } } // 遇到},對象解析結束 reader.endObject(); return sentence; }
JsonReader解析JSON:
注意nextXXX()都會是遊標後移,若是有數據忘了解析等等致使遊標錯位,將會致使數據類型錯亂,這個時候就會很容易發生:java.lang.IllegalStateException: Expected a X but was Y ...參數匹配異常。因此必定不要漏了數據和注意每一次移動遊標。
方式三:使用GSON解析
一、下載Gson包放到項目lib目錄下面,並添加到構建路徑中
gson的jar包下載:gson-2.5.jar
二、編寫JavaBean
package com.example.jsonparsedemo; import java.util.List; // 因爲簡單起見,直接用public public class Sentence { public String caption; public String content; public String dateline; public String fenxiang_img; public String love; public String note; public String picture; public String picture2; public String s_pv; public String sid; public String sp_pv; public String translation; public String tts; public List<Tag> tags; static class Tag{ public int id; public String name; @Override public String toString() { return "id=" + id + "\n" + "name=" + name + "\n" ; } } @Override public String toString() { return "caption=" + caption + "\n" + "content=" + content+ "\n" + "dateline=" + dateline+ "\n" + "fenxiang_img=" + fenxiang_img+ "\n" + "love=" + love + "\n" + "note=" + note + "\n" + "picture=" + picture + "\n" + "picture2=" + picture2 + "\n" + "s_pv=" + s_pv + "\n" + "sid=" + sid + "\n" + "sp_pv="+ sp_pv + "\n" + "translation=" + translation + "\n" + "tts=" + tts + "\n" + "tags=" + tags + "\n"; } }
JavaBean的編寫(重點):
三、新建gson對象解析json,
/** * 經過GSON解析json * @param jsonStr * @return */ public static Sentence parseJsonByGson(String jsonStr){ Gson gson = new Gson(); Sentence sentence = gson.fromJson(jsonStr, Sentence.class); return sentence; }
就三行代碼,沒什麼說的,到這裏三種解析json的方式都介紹完了,感受每種方式都好簡單,想不精通JSON解析都難。
JsonParseUtils.java的完整代碼:
package com.example.jsonparsedemo; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.StringReader; import java.net.HttpURLConnection; import java.net.URL; import java.util.ArrayList; import java.util.List; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import android.annotation.SuppressLint; import android.util.JsonReader; import com.google.gson.Gson; @SuppressLint("NewApi") public class JsonParseUtils { /** * 鏈接網絡請求數據,這裏使用HttpURLConnection */ public static String getJsonData() { URL url = null; String jsonData = ""; // 請求服務器返回的json字符串數據 InputStreamReader in = null; // 讀取的內容(輸入流) try { url = new URL("http://open.iciba.com/dsapi"); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); // 這一步會鏈接網絡獲得輸入流 in = new InputStreamReader(conn.getInputStream()); // 爲輸入建立BufferedReader BufferedReader br = new BufferedReader(in); String inputLine = null; while (((inputLine = br.readLine()) != null)) { jsonData += inputLine; } in.close(); // 關閉InputStreamReader // 斷開網絡鏈接 conn.disconnect(); } catch (Exception ex) { ex.printStackTrace(); } return jsonData; } /** * 經過org.json解析json * * @param jsonStr * json字符串 * @throws JSONException * 格式不對,轉換異常 */ public static Sentence parseJsonByOrgJson(String jsonStr) throws JSONException { // 使用該方法解析思路,遇到大括號用JsonObject,中括號用JsonArray // 第一個是大括號 JSONObject jsonObj = new JSONObject(jsonStr); // 新建Sentence對象 Sentence sentence = new Sentence(); // 如下是無腦操做 String caption = jsonObj.getString("caption"); String content = jsonObj.getString("content"); String dateline = jsonObj.getString("dateline"); String fenxiang_img = jsonObj.getString("fenxiang_img"); String love = jsonObj.getString("love"); String note = jsonObj.getString("note"); String picture = jsonObj.getString("picture"); String picture2 = jsonObj.getString("picture2"); String s_pv = jsonObj.getString("s_pv"); String sid = jsonObj.getString("sid"); String sp_pv = jsonObj.getString("sp_pv"); String translation = jsonObj.getString("translation"); String tts = jsonObj.getString("tts"); sentence.caption = caption; sentence.content = content; sentence.dateline = dateline; sentence.fenxiang_img = fenxiang_img; sentence.love = love; sentence.note = note; sentence.picture = picture; sentence.picture2 = picture2; sentence.s_pv = s_pv; sentence.sid = sid; sentence.sp_pv = sp_pv; sentence.translation = translation; sentence.tts = tts; // 解析關鍵字tags,它是一個JsonArray JSONArray jsonArray = jsonObj.getJSONArray("tags"); // 新建Tag集合 List<Sentence.Tag> tags = new ArrayList<Sentence.Tag>(); for (int i = 0; i < jsonArray.length(); i++) { Sentence.Tag tag = new Sentence.Tag(); // jsonArray裏的每一項都是JsonObject JSONObject jsonObject = jsonArray.getJSONObject(i); tag.id = jsonObject.getInt("id"); tag.name = jsonObject.getString("name"); tags.add(tag); } sentence.tags = tags; return sentence; } /** * Call requires API level 11 (current min is 8): new * android.util.JsonReader 經過org.json解析json * * @param jsonStr * json字符串 * @throws Exception */ @SuppressLint("NewApi") public static Sentence parseJsonByJsonReader(String jsonStr) throws Exception { // 新建Sentence Sentence sentence = new Sentence(); // 新建Tag集合 List<Sentence.Tag> tags = new ArrayList<Sentence.Tag>(); JsonReader reader = new JsonReader(new StringReader(jsonStr)); // 遇到{,開始解析對象 reader.beginObject(); while (reader.hasNext()) { String name = reader.nextName(); if ("caption".equals(name)) { sentence.caption = reader.nextString(); } if ("content".equals(name)) { sentence.content = reader.nextString(); } if ("dateline".equals(name)) { sentence.dateline = reader.nextString(); } if ("fenxiang_img".equals(name)) { sentence.fenxiang_img = reader.nextString(); } if ("love".equals(name)) { sentence.love = reader.nextString(); } if ("note".equals(name)) { sentence.note = reader.nextString(); } if ("picture".equals(name)) { sentence.picture = reader.nextString(); } if ("picture2".equals(name)) { sentence.picture2 = reader.nextString(); } if ("s_pv".equals(name)) { sentence.s_pv = reader.nextString(); } if ("sid".equals(name)) { sentence.sid = reader.nextString(); } if ("sp_pv".equals(name)) { sentence.sp_pv = reader.nextString(); } if ("translation".equals(name)) { sentence.translation = reader.nextString(); } if ("tts".equals(name)) { sentence.tts = reader.nextString(); } if ("tags".equals(name)) { // 遇到[,開始解析數組 reader.beginArray(); while (reader.hasNext()) { // 遇到{,開始解析對象 reader.beginObject(); Sentence.Tag tag = new Sentence.Tag(); if ("id".equals(reader.nextName())) { tag.id = reader.nextInt(); } if ("name".equals(reader.nextName())) { tag.name = reader.nextString(); } // 遇到},對象解析結束 reader.endObject(); tags.add(tag); } sentence.tags = tags; // 遇到],數組解析結束 reader.endArray(); } } // 遇到},對象解析結束 reader.endObject(); return sentence; } /** * 經過GSON解析json * @param jsonStr * @return */ public static Sentence parseJsonByGson(String jsonStr){ Gson gson = new Gson(); Sentence sentence = gson.fromJson(jsonStr, Sentence.class); return sentence; } }
因爲本篇文章並不打算將解析的數據用android控件顯示出來,只是解析json數據,有了數據還不會用嗎,哈哈,數據在手,天下我有。下面咱們經過Android的單元測試3種方式解析的結果。
其實Android的單元測試已經在【XML解析(一)】SAX解析XML文章中介紹過了,這裏爲了完整性及照顧新手,這裏在說一遍吧,也能夠去看那篇文章。
Android單元測試
第一步:環境搭建
<instrumentation android:targetPackage="com.example.jsonparsedemo" android:name="android.test.InstrumentationTestRunner"></instrumentation>
第二步: 新建一個測試類JsonParseTest.java(測試的類能夠放在該應用的任何包下面,但必須繼承AndroidTestCase)
/** * 測試obj.json解析json */ public void testObjJsonParseJson() throws Exception{ Log.e("obj.json", "-------------------------"); String jsonData = JsonParseUtils.getJsonData(); Sentence sentence = JsonParseUtils.parseJsonByOrgJson(jsonData); Log.e("result", sentence.toString()); }
/** * 測試JsonReader解析json */ public void testJsonReaderParseJson() throws Exception{ Log.e("JsonReader", "-------------------------"); String jsonData = JsonParseUtils.getJsonData(); Sentence sentence = JsonParseUtils.parseJsonByJsonReader(jsonData); Log.e("result", sentence.toString()); }
/** * 測試JsonReader解析json */ public void testGsonParseJson() throws Exception{ Log.e("gson", "-------------------------"); String jsonData = JsonParseUtils.getJsonData(); Sentence sentence = JsonParseUtils.parseJsonByGson(jsonData); Log.e("result", sentence.toString()); }
分別運行上面的三個方法,Run As Android JUnit Test
測試結果:
OK,三種方法都成功解析json,是否是感受json解析簡直是太簡單了,簡單到不想解析。
因爲我的水平有限,文章所介紹的知識有錯誤的地方,歡迎你們指出,與君共勉,一塊兒進步。
下篇文章:【解析HTML】HTML解析,網絡爬蟲。敬請期待。