概述
在網絡中,數據交互通常是以XML和Json的格式進行,所以對這兩種格式的數據進行解析,是Android開發中的必備功能,本文以一個簡單的小例子,簡述Android開發中Xml和Json解析的常用方式,僅供學習分享使用。
XML解析
Android 提供了三種解析XML的方式:SAX(Simple API XML), DOM(Document Object Model), PULL,本文主要講解Pull的方式解析Xml。
PULL解析Xml優點:PULL解析器小巧輕便,解析速度快,簡單易用,非常適合在Android移動設備中使用,Android系統內部在解析各種XML時也是用PULL解析器,Android官方推薦開發者們使用Pull解析技術。Pull解析技術是第三方開發的開源技術,它同樣可以應用於JavaSE開發。
涉及知識點
- XmlPullParser 是一個提供對XML進行Pull方式解析的基礎功能的接口。
- xmlPullParser.getEventType() 返回當前節點的事件類型(如:START_TAG, END_TAG, TEXT, etc.)。
- xmlPullParser.getName() 獲取當前節點對應的名稱。
- xmlPullParser.getAttributeCount() 獲取當前節點對應的屬性個數。
- xmlPullParser.getText() 獲取當前節點對應的文本內容。
- xmlPullParser.getAttributeName(0) 獲取屬性對應的名稱。
- xmlPullParser.getAttributeValue(0) 獲取屬性對應的值。
- xmlPullParser.next() 移動到下一個事件。
Xml文件
Xml存放相對路徑:DemoXml\app\src\main\res\xml\test.xml [xml文件夾]
1 <bookstore> 2 <book category="COOKING"> 3 <title lang="en">Everyday Italian</title> 4 <author>Giada De Laurentiis</author> 5 <year>2005</year> 6 <price>30.00</price> 7 </book> 8 <book category="CHILDREN"> 9 <title lang="en">Harry Potter</title> 10 <author>J K. Rowling</author> 11 <year>2005</year> 12 <price>29.99</price> 13 </book> 14 <book category="WEB"> 15 <title lang="en">Learning XML</title> 16 <author>Erik T. Ray</author> 17 <year>2003</year> 18 <price>39.95</price> 19 </book> 20 </bookstore>
Xml解析源碼
1 /** 2 * 獲取Xml內容 3 * @param resources 4 * @param id 5 * @return 6 * @throws XmlPullParserException 7 * @throws IOException 8 */ 9 private List<String> xml_parser(Resources resources, int id) throws XmlPullParserException, IOException { 10 XmlPullParser xmlPullParser = resources.getXml(id); 11 List<String> lstContent=new ArrayList<String>(); 12 int eventType = xmlPullParser.getEventType(); 13 while (eventType != XmlPullParser.END_DOCUMENT) { 14 switch (eventType) { 15 case XmlPullParser.START_DOCUMENT://文檔開始 16 Log.i(TAG, "xml_parser: START_DOCUMENT"); 17 break; 18 case XmlPullParser.END_DOCUMENT://文檔結束 19 Log.i(TAG, "xml_parser: END_DOCUMENT"); 20 break; 21 case XmlPullParser.START_TAG://標記(元素,節點)開始 22 Log.i(TAG, "xml_parser: START_TAG"); 23 String tagName = xmlPullParser.getName(); 24 //有些節點是沒有屬性值的,所以需要判斷,否則會越界 25 int count = xmlPullParser.getAttributeCount();//獲取屬性個個數 26 String tagAttributeValue=""; 27 String tagAttributeName=""; 28 //String text =xmlPullParser.getText();//此處獲取不到text 29 String content=""; 30 if (count > 0) { 31 tagAttributeName=xmlPullParser.getAttributeName(0); 32 tagAttributeValue = xmlPullParser.getAttributeValue(0); 33 content="標簽="+tagName+"屬性名="+tagAttributeName+"屬性值="+tagAttributeValue; 34 }else{ 35 content="標簽="+tagName; 36 } 37 lstContent.add(content); 38 break; 39 case XmlPullParser.TEXT: 40 String text =xmlPullParser.getText(); 41 lstContent.add("節點內容="+text); 42 break; 43 case XmlPullParser.END_TAG://標記結束 44 Log.i(TAG, "xml_parser: END_TAG"); 45 break; 46 } 47 eventType = xmlPullParser.next(); 48 } 49 return lstContent; 50 }
如果Xml文件過大的話,則不適合在Activity主線程中執行,本文是在Worker線程中執行的,如下所示:
1 private static final String TAG="TAG"; 2 3 private static final int MSG_FINISH=0x0001; 4 5 private TextView tvMsg; 6 7 private Handler handler=new Handler(){ 8 @Override 9 public void handleMessage(Message msg) { 10 switch (msg.what){ 11 case MSG_FINISH: 12 List<String> lstContent=(List<String>)msg.obj; 13 for (String info :lstContent){ 14 tvMsg.append(info+"\r\n"); 15 } 16 break; 17 } 18 } 19 }; 20 21 public void bn_xml_parser_click(View view){ 22 tvMsg.setText(""); 23 new Thread(){ 24 @Override 25 public void run() { 26 try { 27 List<String> lstContent=xml_parser(getResources(),R.xml.test); 28 Message msg=handler.obtainMessage(); 29 msg.what=MSG_FINISH; 30 msg.obj=lstContent; 31 handler.sendMessage(msg); 32 } catch (XmlPullParserException e) { 33 e.printStackTrace(); 34 } catch (IOException e) { 35 e.printStackTrace(); 36 } 37 } 38 }.start(); 39 }
JSON解析
Json是一種輕量級的數據交換格式,具有良好的可讀和便於快速編寫的特性。業內主流技術為其提供了完整的解決方案,從而可以在不同平台間進行數據交換。
涉及知識點
- JSONObject 表示一個Json格式的對象。
- jsonObject.getString("key"); 獲取字符串格式的值。
- jsonObject.getInt("key"); 獲取Int類型的值。
- jsonObject.getBoolean("key"); 獲取bool類型的值。
- jsonObject.getDouble("key"); 獲取浮點數類型的值。
- jsonObject.get("key"); 返回Object類型的對象。
- jsonObject.getJSONArray("key"); 返回數據類型的對象。
- InputStream 輸入流。
Json文件
Json存放相對路徑:DemoXml\app\src\main\res\raw\test2.json [raw文件夾]
{
"name": "小明",
"age": 14,
"gender": true,
"height": 1.65,
"grade": null,
"middle_school": "\"W3C\" Middle School",
"skills": [
"JavaScript",
"Java",
"Python",
"Lisp"
]
}
Json解析源碼
1 /** 2 * 解析到列表 3 * @return 4 * @throws IOException 5 * @throws JSONException 6 */ 7 private List<String> json_parser() throws IOException, JSONException { 8 List<String> lstContent = new ArrayList<String>(); 9 String data = getContent(getResources(), R.raw.test2); 10 JSONObject jsonObject = new JSONObject(data); 11 String name = jsonObject.getString("name"); 12 int age = jsonObject.getInt("age"); 13 boolean gender = jsonObject.getBoolean("gender"); 14 double height = jsonObject.getDouble("height"); 15 Object grade = jsonObject.get("grade"); 16 String middleSchool = jsonObject.getString("middle_school"); 17 JSONArray jsonArray = jsonObject.getJSONArray("skills"); 18 lstContent.add("name=" + name); 19 lstContent.add("age=" + age); 20 lstContent.add("gender=" + gender); 21 lstContent.add("height=" + height); 22 lstContent.add("grade=" + grade); 23 lstContent.add("middleSchool=" + middleSchool); 24 for (int i = 0; i < jsonArray.length(); i++) { 25 String skill = jsonArray.getString(i); 26 lstContent.add("skill=" + skill); 27 } 28 return lstContent; 29 } 30 31 /** 32 * 通過id獲取Json文件對應的內容 33 * @param resources 34 * @param id 35 * @return 36 * @throws IOException 37 */ 38 private String getContent(Resources resources, int id) throws IOException { 39 StringBuilder stringBuilder = new StringBuilder(); 40 InputStream inputStream = null; 41 try { 42 inputStream = resources.openRawResource(id); 43 byte[] bytes = new byte[1024]; 44 int length = inputStream.read(bytes, 0, 1024); 45 while (length > -1) { 46 stringBuilder.append(new String(bytes, 0, length)); 47 length = inputStream.read(bytes, 0, 1024); 48 } 49 } finally { 50 if (inputStream != null) { 51 inputStream.close(); 52 } 53 } 54 return stringBuilder.toString(); 55 }
同樣,如果Json文件比較大,或者解析比較慢,則不能在Activity主線程中執行,需要新啟動一個Worker線程,在后台執行,如下所示:
1 private static final String TAG="TAG"; 2 3 private static final int MSG_FINISH=0x0001; 4 5 private static final int MSG_SERIALIZE=0x0002; 6 7 private TextView tvMsg; 8 9 private Handler handler=new Handler(){ 10 @Override 11 public void handleMessage(Message msg) { 12 switch (msg.what){ 13 case MSG_FINISH: 14 List<String> lstContent=(List<String>)msg.obj; 15 for (String info :lstContent){ 16 tvMsg.append(info+"\r\n"); 17 } 18 break; 19 } 20 } 21 }; 22 23 /** 24 * 解析Json 25 * @param view 26 */ 27 public void bn_json_parser_click(View view) { 28 tvMsg.setText(""); 29 new Thread() { 30 @Override 31 public void run() { 32 try { 33 List<String> lstContent = json_parser(); 34 Message msg = handler.obtainMessage(); 35 msg.what = MSG_FINISH; 36 msg.obj = lstContent; 37 handler.sendMessage(msg); 38 } catch (IOException e) { 39 e.printStackTrace(); 40 } catch (JSONException e) { 41 e.printStackTrace(); 42 } 43 } 44 }.start(); 45 }
如果需要將Json反序列化成類對象,或者將類對象序列化成Json格式文件,如下是一個幫助類:
1 package com.hex.demoxml; 2 3 import android.util.Log; 4 5 import java.util.Collection; 6 import java.lang.reflect.Array; 7 import java.lang.reflect.Field; 8 import java.lang.reflect.ParameterizedType; 9 import java.lang.reflect.Type; 10 import java.util.Collection; 11 import org.json.JSONArray; 12 import org.json.JSONException; 13 import org.json.JSONObject; 14 import org.json.JSONStringer; 15 16 /** JSON序列化輔助類 **/ 17 public class JsonHelper { 18 private static final String TAG="TAG"; 19 /** 20 * 將對象轉換成Json字符串 21 **/ 22 public static String toJSON(Object obj) { 23 JSONStringer js = new JSONStringer(); 24 serialize(js, obj); 25 return js.toString(); 26 } 27 28 /** 29 * 序列化為JSON 30 **/ 31 private static void serialize(JSONStringer js, Object o) { 32 if (isNull(o)) { 33 try { 34 js.value(null); 35 } catch (JSONException e) { 36 e.printStackTrace(); 37 } 38 return; 39 } 40 41 Class<?> clazz = o.getClass(); 42 if (isObject(clazz)) { // 對象 43 serializeObject(js, o); 44 } else if (isArray(clazz)) { // 數組 45 serializeArray(js, o); 46 } else if (isCollection(clazz)) { // 集合 47 Collection<?> collection = (Collection<?>) o; 48 serializeCollect(js, collection); 49 } else { // 單個值 50 try { 51 js.value(o); 52 } catch (JSONException e) { 53 e.printStackTrace(); 54 } 55 } 56 } 57 58 /** 59 * 序列化數組 60 **/ 61 private static void serializeArray(JSONStringer js, Object array) { 62 try { 63 js.array(); 64 for (int i = 0; i < Array.getLength(array); ++i) { 65 Object o = Array.get(array, i); 66 serialize(js, o); 67 } 68 js.endArray(); 69 } catch (Exception e) { 70 e.printStackTrace(); 71 } 72 } 73 74 /** 75 * 序列化集合 76 **/ 77 private static void serializeCollect(JSONStringer js, Collection<?> collection) { 78 try { 79 js.array(); 80 for (Object o : collection) { 81 serialize(js, o); 82 } 83 js.endArray(); 84 } catch (Exception e) { 85 e.printStackTrace(); 86 } 87 } 88 89 /** 90 * 序列化對象 91 **/ 92 private static void serializeObject(JSONStringer js, Object obj) { 93 try { 94 js.object(); 95 for (Field f : obj.getClass().getFields()) { 96 Object o = f.get(obj); 97 js.key(f.getName()); 98 serialize(js, o); 99 } 100 js.endObject(); 101 } catch (Exception e) { 102 e.printStackTrace(); 103 } 104 } 105 106 /** 107 * 反序列化簡單對象 108 * 109 * @throws 110 **/ 111 public static <T> T parseObject(JSONObject jo, Class<T> clazz) { 112 Log.i(TAG, "parseObject: >>>>>>第二個開始"); 113 if (clazz == null || isNull(jo)) { 114 Log.i(TAG, "parseObject: >>>>>>第二個parseObject"); 115 return null; 116 } 117 118 T obj = createInstance(clazz); 119 if (obj == null) { 120 Log.i(TAG, "parseObject: >>>>>>創建實例為空"); 121 return null; 122 } 123 Log.i(TAG, "parseObject: >>>>>>屬性長度"+clazz.getFields().length); 124 Log.i(TAG, "parseObject: >>>>>>屬性長度2"+clazz.getClass()); 125 for (Field f : clazz.getFields()) { 126 Log.i(TAG, "parseObject: >>>>>>"+f.getName()); 127 setField(obj, f, jo); 128 //Log.i(TAG, "parseObject: >>>>>>"+obj.); 129 } 130 Log.i(TAG, "parseObject: >>>>>返回obj"+obj.getClass()); 131 return obj; 132 } 133 134 /** 135 * 反序列化簡單對象 136 * 137 * @throws 138 **/ 139 public static <T> T parseObject(String jsonString, Class<T> clazz) { 140 if (clazz == null || jsonString == null || jsonString.length() == 0) { 141 Log.i(TAG, "parseObject: >>>>>>>null"); 142 return null; 143 } 144 Log.i(TAG, "parseObject: >>>>>>>not null"); 145 JSONObject jo = null; 146 try { 147 jo = new JSONObject(jsonString); 148 } catch (JSONException e) { 149 Log.i(TAG, "parseObject: >>>>>>轉換json對象異常:"+e.getMessage()); 150 e.printStackTrace(); 151 } 152 153 if (isNull(jo)) { 154 Log.i(TAG, "parseObject: >>>>>轉換后為null"); 155 return null; 156 } 157 Log.i(TAG, "parseObject: >>>>>>進入下一步"); 158 return parseObject(jo, clazz); 159 } 160 161 /** 162 * 反序列化數組對象 163 * 164 * @throws 165 **/ 166 public static <T> T[] parseArray(JSONArray ja, Class<T> clazz) { 167 if (clazz == null || isNull(ja)) { 168 return null; 169 } 170 171 int len = ja.length(); 172 Log.i(TAG, "parseArray: >>>>>"+len); 173 Log.i(TAG, "parseArray: >>>>>"+clazz.getName()); 174 @SuppressWarnings("unchecked") 175 T[] array = (T[]) Array.newInstance(clazz, len); 176 177 for (int i = 0; i < len; ++i) { 178 try { 179 Object object=ja.get(i); 180 if(isSingle(clazz)){ 181 Log.i(TAG, "parseArray: >>>>>:"+object.toString()); 182 array[i]=(T)object.toString(); 183 }else { 184 JSONObject jo = ja.getJSONObject(i); 185 Log.i(TAG, "parseArray: >>>>>jo:"+jo.toString()); 186 T o = parseObject(jo, clazz); 187 Log.i(TAG, "parseArray: >>>>>o:" + o.toString()); 188 array[i] = o; 189 } 190 } catch (JSONException e) { 191 e.printStackTrace(); 192 } 193 } 194 195 return array; 196 } 197 198 /** 199 * 反序列化數組對象 200 * 201 * @throws 202 **/ 203 public static <T> T[] parseArray(String jsonString, Class<T> clazz) { 204 if (clazz == null || jsonString == null || jsonString.length() == 0) { 205 return null; 206 } 207 JSONArray jo = null; 208 try { 209 jo = new JSONArray(jsonString); 210 } catch (JSONException e) { 211 e.printStackTrace(); 212 } 213 214 if (isNull(jo)) { 215 return null; 216 } 217 218 return parseArray(jo, clazz); 219 } 220 221 /** 222 * 反序列化泛型集合 223 * 224 * @throws 225 **/ 226 @SuppressWarnings("unchecked") 227 public static <T> Collection<T> parseCollection(JSONArray ja, Class<?> collectionClazz, 228 Class<T> genericType) { 229 230 if (collectionClazz == null || genericType == null || isNull(ja)) { 231 return null; 232 } 233 234 Collection<T> collection = (Collection<T>) createInstance(collectionClazz); 235 236 for (int i = 0; i < ja.length(); ++i) { 237 try { 238 JSONObject jo = ja.getJSONObject(i); 239 T o = parseObject(jo, genericType); 240 collection.add(o); 241 } catch (JSONException e) { 242 e.printStackTrace(); 243 } 244 } 245 246 return collection; 247 } 248 249 /** 250 * 反序列化泛型集合 251 * 252 * @throws 253 **/ 254 public static <T> Collection<T> parseCollection(String jsonString, Class<?> collectionClazz, 255 Class<T> genericType) { 256 if (collectionClazz == null || genericType == null || jsonString == null 257 || jsonString.length() == 0) { 258 return null; 259 } 260 JSONArray jo = null; 261 try { 262 jo = new JSONArray(jsonString); 263 } catch (JSONException e) { 264 e.printStackTrace(); 265 } 266 267 if (isNull(jo)) { 268 return null; 269 } 270 271 return parseCollection(jo, collectionClazz, genericType); 272 } 273 274 /** 275 * 根據類型創建對象 276 **/ 277 private static <T> T createInstance(Class<T> clazz) { 278 if (clazz == null) 279 return null; 280 T obj = null; 281 try { 282 obj = clazz.newInstance(); 283 } catch (Exception e) { 284 Log.i(TAG, "createInstance: >>>>>>創建實例異常"); 285 e.printStackTrace(); 286 } 287 return obj; 288 } 289 290 /** 291 * 設定字段的值 292 **/ 293 private static void setField(Object obj, Field f, JSONObject jo) { 294 String name = f.getName(); 295 Class<?> clazz = f.getType(); 296 Log.i(TAG, "setField: >>>>>name:"+name); 297 try { 298 if (isArray(clazz)) { // 數組 299 Log.i(TAG, "setField: >>>>>數組"); 300 Class<?> c = clazz.getComponentType(); 301 JSONArray ja = jo.optJSONArray(name); 302 if (!isNull(ja)) { 303 Log.i(TAG, "setField: >>>>>ja:"+ja.getString(0)); 304 Object array = parseArray(ja, c); 305 f.set(obj, array); 306 }else{ 307 Log.i(TAG, "setField: >>>>>數組為空"); 308 } 309 } else if (isCollection(clazz)) { // 泛型集合 310 Log.i(TAG, "setField: >>>>>泛型集合"); 311 // 獲取定義的泛型類型 312 Class<?> c = null; 313 Type gType = f.getGenericType(); 314 if (gType instanceof ParameterizedType) { 315 ParameterizedType ptype = (ParameterizedType) gType; 316 Type[] targs = ptype.getActualTypeArguments(); 317 if (targs != null && targs.length > 0) { 318 Type t = targs[0]; 319 c = (Class<?>) t; 320 } 321 } 322 323 JSONArray ja = jo.optJSONArray(name); 324 if (!isNull(ja)) { 325 Object o = parseCollection(ja, clazz, c); 326 f.set(obj, o); 327 } 328 } else if (isSingle(clazz)) { // 值類型 329 Log.i(TAG, "setField: >>>>>Single值類型"); 330 Object o = jo.opt(name); 331 if (o != null) { 332 f.set(obj, o); 333 } 334 } else if (isObject(clazz)) { // 對象 335 Log.i(TAG, "setField: >>>>>Object對象:"+clazz); 336 JSONObject j = jo.optJSONObject(name); 337 if (!isNull(j)) { 338 339 Object o = parseObject(j, clazz); 340 f.set(obj, o); 341 }else{ 342 Log.i(TAG, "setField: >>>>>Object對象為null"); 343 } 344 } else { 345 Log.i(TAG, "setField: >>>>>未知類型:"+clazz); 346 throw new Exception("unknow type!"); 347 } 348 } catch (Exception e) { 349 e.printStackTrace(); 350 } 351 } 352 353 /** 354 * 判斷對象是否為空 355 **/ 356 private static boolean isNull(Object obj) { 357 if (obj instanceof JSONObject) { 358 return JSONObject.NULL.equals(obj); 359 } 360 return obj == null; 361 } 362 363 /** 364 * 判斷是否是值類型 365 **/ 366 private static boolean isSingle(Class<?> clazz) { 367 return isBoolean(clazz) || isNumber(clazz) || isString(clazz); 368 } 369 370 /** 371 * 是否布爾值 372 **/ 373 public static boolean isBoolean(Class<?> clazz) { 374 return (clazz != null) 375 && ((Boolean.TYPE.isAssignableFrom(clazz)) || (Boolean.class 376 .isAssignableFrom(clazz))); 377 } 378 379 /** 380 * 是否數值 381 **/ 382 public static boolean isNumber(Class<?> clazz) { 383 return (clazz != null) 384 && ((Byte.TYPE.isAssignableFrom(clazz)) || (Short.TYPE.isAssignableFrom(clazz)) 385 || (Integer.TYPE.isAssignableFrom(clazz)) 386 || (Long.TYPE.isAssignableFrom(clazz)) 387 || (Float.TYPE.isAssignableFrom(clazz)) 388 || (Double.TYPE.isAssignableFrom(clazz)) || (Number.class 389 .isAssignableFrom(clazz))); 390 } 391 392 /** 393 * 判斷是否是字符串 394 **/ 395 public static boolean isString(Class<?> clazz) { 396 return (clazz != null) 397 && ((String.class.isAssignableFrom(clazz)) 398 || (Character.TYPE.isAssignableFrom(clazz)) || (Character.class 399 .isAssignableFrom(clazz))); 400 } 401 402 /** 403 * 判斷是否是對象 404 **/ 405 private static boolean isObject(Class<?> clazz) { 406 return clazz != null && !isSingle(clazz) && !isArray(clazz) && !isCollection(clazz); 407 } 408 409 /** 410 * 判斷是否是數組 411 **/ 412 public static boolean isArray(Class<?> clazz) { 413 return clazz != null && clazz.isArray(); 414 } 415 416 /** 417 * 判斷是否是集合 418 **/ 419 public static boolean isCollection(Class<?> clazz) { 420 return clazz != null && Collection.class.isAssignableFrom(clazz); 421 } 422 }
備注
沉舟側畔千帆過,病樹前頭萬木春。
