概述
在网络中,数据交互通常是以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 }
View Code
备注
沉舟侧畔千帆过,病树前头万木春。