一起学Android之Xml与Json解析
概述
在网络中,数据交互通常是以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 }
备注
沉舟侧畔千帆过,病树前头万木春。
上一篇: 颛顼到底是历史人物还是神话?真相是什么
下一篇: 陈登:刘备心中的头号英雄,还数次击败孙策