一起学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 }
备注
沉舟侧畔千帆过,病树前头万木春。
作者:老码识途
出处:http://www.cnblogs.com/hsiang/
本文版权归作者和博客园共有,写文不易,支持原创,欢迎转载【点赞】,转载请保留此段声明,且在文章页面明显位置给出原文连接,谢谢。
关注个人公众号,定时同步更新技术及职场文章
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
2017-08-03 C# 实现中国象棋【棋盘,棋子】