Android学习系列(19)-App数据格式之解析Xml

转载请注明出处:http://blog.csdn.net/stevenhu_223/article/details/42520233

         本博文相关的Demo下载链接:http://download.csdn.net/detail/stevenhu_223/8340451

  前言:在开发Android第三方App应用的过程中,特别是涉及到网络请求的App,都会涉及到解析后台返回的数据。而后台返回的数据无非就是两种格式,xml和json格式。如何更好的方便有效的解析这些后台返回的数据,对我们开发者来说是很重要的。接下来将介绍以下几种笔者比较常用的数据解析方式。


   一、simple-xml第三方jar包解析xml格式数据

    simple-xml是一个xml和对象互转操作工具包,官方网址为:http://simple.sourceforge.net/,jar包可以到官网上下载,笔者使用的是目前最新版本的jar包,名为simple-xml-2.7.1.jar;废话不多说了,代码才是最真实靠谱的力证。

    下面是整个Demo工程文件截图,如下图:

Android学习系列(19)-App数据格式之解析Xml_第1张图片

    该Demo主要是通过simple-xml解析assets目录中的data.xml文件内容数据,然后显示出来;

    1.data.xml文件内容如下:

[html] view plain copy
  1. xml version="1.0" encoding="utf-8"?>  
  2. <resources>  
  3. xml version="1.0" encoding="utf-8"?>  
  4.     <dataContent>  
  5.         <group>  
  6.             <groupID>1groupID>  
  7.             <groupName>第一组groupName>  
  8.             <member>  
  9.                 <name>张三name>  
  10.                 <age>22age>  
  11.             member>  
  12.             <member>  
  13.                 <name>李四name>  
  14.                 <age>24age>  
  15.             member>  
  16.             <member>  
  17.                 <name>欧阳雪name>  
  18.                 <age>18age>  
  19.             member>  
  20.         group>  
  21.         <group>  
  22.             <groupID>2groupID>  
  23.             <groupName>第二组groupName>  
  24.             <member>  
  25.                 <name>司徒静name>  
  26.                 <age>19age>  
  27.             member>  
  28.             <member>  
  29.                 <name>叶笙name>  
  30.                 <age>26age>  
  31.             member>  
  32.             <member>  
  33.                 <name>杨风name>  
  34.                 <age>25age>  
  35.             member>  
  36.         group>  
  37.         <group>  
  38.             <groupID>3groupID>  
  39.             <groupName>第三组groupName>  
  40.             <member>  
  41.                 <name>王龙name>  
  42.                 <age>32age>  
  43.             member>  
  44.             <member>  
  45.                 <name>西门胜男name>  
  46.                 <age>21age>  
  47.             member>  
  48.             <member>  
  49.                 <name>张铬name>  
  50.                 <age>45age>  
  51.             member>  
  52.         group>  
  53.     dataContent>  
  54.   
  55. resources>  
   通过上面的文件内容,我们知道,这个文件内容主要有三组数据,每组数据有个三个成员组,每个成员组都有名字和年龄这两个子元素。Demo中将这些解析出来内容通过ExpandableListView显示出来。

  2.主页面MainActivity代码如下:

[java] view plain copy
  1. package com.steven.android.simple.xml.activity;  
  2.   
  3. import java.io.BufferedReader;  
  4. import java.io.IOException;  
  5. import java.io.InputStream;  
  6. import java.io.InputStreamReader;  
  7. import java.util.regex.Matcher;  
  8. import java.util.regex.Pattern;  
  9. import org.simpleframework.xml.core.Persister;  
  10. import android.app.Activity;  
  11. import android.os.Bundle;  
  12. import android.text.TextUtils;  
  13. import android.util.Log;  
  14. import android.view.Menu;  
  15. import android.widget.ExpandableListView;  
  16. import com.steven.android.simple.xml.adapter.ExpandAdapter;  
  17. import com.steven.android.simple.xml.parse.DataParseResponse;  
  18. /** 
  19.  * 描述:主页面 
  20.  * @author stevenhu223 
  21.  * 
  22.  */  
  23. public class MainActivity extends Activity {  
  24.   
  25.     private  final String TAG = "MainActivity";  
  26.     private ExpandableListView mExpandableListView;  
  27.     private ExpandAdapter mAdapter;  
  28.   
  29.     @Override  
  30.     protected void onCreate(Bundle savedInstanceState) {  
  31.         super.onCreate(savedInstanceState);  
  32.         setContentView(R.layout.activity_main);  
  33.         mExpandableListView = (ExpandableListView) findViewById(R.id.expanlist_content);  
  34.         try {  
  35.             matchAndParseData();  
  36.         } catch (Exception e) {  
  37.             // TODO Auto-generated catch block  
  38.             e.printStackTrace();  
  39.         }  
  40.     }  
  41.   
  42.     @Override  
  43.     public boolean onCreateOptionsMenu(Menu menu) {  
  44.         // Inflate the menu; this adds items to the action bar if it is present.  
  45.         getMenuInflater().inflate(R.menu.main, menu);  
  46.         return true;  
  47.     }  
  48.   
  49.     /** 
  50.      * 匹配获取和解析xml文件内容 
  51.      * @throws Exception 
  52.      */  
  53.     private void matchAndParseData() throws Exception {  
  54.         InputStream inputStream = getResources().getAssets().open("data.xml");  
  55.         String dataContent = convertStreamToString(inputStream);  
  56.         String content = "";  
  57.         //正则表达式匹配  
  58.         Pattern DATA_PATTERN= Pattern.compile("[\\S\\s]*([\\s\\S]*)[\\s\\S]*");  
  59.         Matcher matcher = DATA_PATTERN.matcher(dataContent);  
  60.         if (matcher.matches()) {  
  61.             //获取包含dataContent元素的内容  
  62.             content = matcher.group(1);  
  63.         }   
  64.         if (!TextUtils.isEmpty(content)) {  
  65.             DataParseResponse dataResponse = parseToBean(DataParseResponse.class, content);  
  66.             mAdapter = new ExpandAdapter(this, dataResponse.mGroupEntities);  
  67.             mExpandableListView.setAdapter(mAdapter);  
  68.         }  
  69.     }  
  70.   
  71.     /** 
  72.      * 将xml文件内容解析成实体类 
  73.      * @param type 
  74.      * @param data 
  75.      * @return 
  76.      */  
  77.     private  T parseToBean(Class type , String data) {  
  78.   
  79.         try {  
  80.             return new Persister().read(type, data, false);  
  81.         } catch (Exception e) {  
  82.             Log.e(TAG, "parse Data error", e);  
  83.             throw new RuntimeException(e);  
  84.         }  
  85.       
  86.     }  
  87.       
  88.     /** 
  89.      * 输入流转字符串 
  90.      * @param is 
  91.      * @return 
  92.      */  
  93.     public String convertStreamToString(InputStream is) {  
  94.   
  95.         BufferedReader reader = new BufferedReader(new InputStreamReader(is));  
  96.         StringBuilder sb = new StringBuilder();  
  97.         String line = null;  
  98.         try {  
  99.             while ((line = reader.readLine()) != null) {  
  100.                 sb.append(line);  
  101.             }  
  102.         } catch (IOException e) {  
  103.             e.printStackTrace();  
  104.         } finally {  
  105.             try {  
  106.                 is.close();  
  107.             } catch (IOException e) {  
  108.                 e.printStackTrace();  
  109.             }  
  110.         }  
  111.         return sb.toString();  
  112.   
  113.     }  
  114. }  
  上面的代码中,parseToBean方法的功能就是将xml格式数据解析成对应的实体类,Persister类是simple-xml包中的类。通过调用parseToBean函数将xml内容数据解析封装成DataParseResponse对象,接下来我们看看DataParseResponse的代码。

   3.DataParseResponse.Java文件代码如下:

[java] view plain copy
  1. package com.steven.android.simple.xml.parse;  
  2.   
  3. import org.simpleframework.xml.ElementList;  
  4. import org.simpleframework.xml.Root;  
  5.   
  6. import com.steven.android.simple.xml.entity.GroupEntity;  
  7.   
  8. import java.util.List;  
  9.   
  10. /** 
  11.  *  描述:解析数据响应类 
  12.  * 此处的dataContent要对应xml文件中的dataContent元素 
  13.  * @author stenvenhu223 
  14.  * 
  15.  */  
  16. @Root(name = "dataContent")  
  17. public class DataParseResponse {  
  18.     @ElementList(inline=true,required=false)  
  19.     public List mGroupEntities;  
  20. }  
  通过上面的代码我们知道,simple-xml包解析xml格式数据成实体类时,实体类中对应需要解析的xml格式数据元素名的注解是非常重要的。这些注释都是来自simple-xml包的。DataParseResponse类中的@Root(name = "NewDataSet")注解表示的是从xml数据根元素dataContent。由于group元素在根元素dataContent中是以数组的形式存在的,所以这里的集合mGroupEntities就表示解析的group元素数组内容集合,必然的它的注解也应为@ElementList(inline=true,required=false)。接下来,我们看看GroupEntity实体类的代码。

 4.GroupEntity.java文件代码如下:

[java] view plain copy
  1. package com.steven.android.simple.xml.entity;  
  2.   
  3. import java.util.List;  
  4.   
  5. import org.simpleframework.xml.Element;  
  6. import org.simpleframework.xml.ElementList;  
  7. import org.simpleframework.xml.Root;  
  8. @Root(name="group")  
  9. public class GroupEntity {  
  10.     @Element(name="groupID"public String groupId;  
  11.     @Element(name="groupName"public String groupName;  
  12.     @ElementList(inline=true,required=false)  
  13.     public List memberEntities;  
  14.       
  15. }  
   代码中,@Root(name="group")对应的是xml文件中的group元素。@Element(name="groupID")注解对应的是group元素的子元素groupID,@Element(name="groupName")注解对应的是group元素的子元素groupName。而member元素在group元素中是以数组形式存在的,所以它在GroupEntity中必然也以集合的形式存在,注解也应该为@ElementList(inline=true,required=false);接着,我们解析看看实体类MemberEntity的代码。

   5.MemberEntity.java文件代码如下:

[java] view plain copy
  1. @Root(name="member")  
  2. public class MemberEntity {  
  3.     @Element(required=falsepublic String name;  
  4.     @Element(required=falsepublic String age;  
  5. }  
   MemberEntity代码中的代码注释这里就不多说了,原理和其他的实体类是一致的。

   既然要把解析出来的数据通过ExpandableListView显示出来,那么我们就需要创建ExpandableListView对应的适配器,然后填充解析后的实体类形式数据。我们来看看适配器ExpandAdapter的代码。

   6.ExpandAdapter.java文件代码如下:

[java] view plain copy
  1. package com.steven.android.simple.xml.adapter;  
  2.   
  3. import java.util.List;  
  4. import android.content.Context;  
  5. import android.view.LayoutInflater;  
  6. import android.view.View;  
  7. import android.view.ViewGroup;  
  8. import android.widget.BaseExpandableListAdapter;  
  9. import android.widget.TextView;  
  10. import com.steven.android.simple.xml.activity.R;  
  11. import com.steven.android.simple.xml.custom.ViewHolder;  
  12. import com.steven.android.simple.xml.entity.GroupEntity;  
  13. import com.steven.android.simple.xml.entity.MemberEntity;  
  14.   
  15. public class ExpandAdapter extends BaseExpandableListAdapter{  
  16.   
  17.     private List mGroupEntities;  
  18.     private LayoutInflater mInflater;  
  19.       
  20.     public  ExpandAdapter(Context context, List list) {  
  21.         mGroupEntities = list;  
  22.         mInflater = LayoutInflater.from(context);  
  23.     }  
  24.       
  25.     @Override  
  26.     public Object getChild(int groupPosition, int childPosition) {  
  27.         // TODO Auto-generated method stub  
  28.         return mGroupEntities.get(groupPosition).memberEntities.get(childPosition);  
  29.     }  
  30.   
  31.     @Override  
  32.     public long getChildId(int groupPosition, int childPosition) {  
  33.         // TODO Auto-generated method stub  
  34.         return childPosition;  
  35.     }  
  36.   
  37.     @Override  
  38.     public View getChildView(int groupPosition, int childPosition,  
  39.             boolean isLastChild, View convertView, ViewGroup parent) {  
  40.         if (convertView == null) {  
  41.             convertView = mInflater.inflate(R.layout.item_member_content, parent, false);  
  42.         }  
  43.         TextView text_member_content = ViewHolder.get(convertView, R.id.text_member_content);  
  44.         MemberEntity entity = (MemberEntity)getChild(groupPosition, childPosition);  
  45.         text_member_content.setText(entity.name);  
  46.         return convertView;  
  47.     }  
  48.   
  49.     @Override  
  50.     public int getChildrenCount(int groupPosition) {  
  51.         // TODO Auto-generated method stub  
  52.         return mGroupEntities.get(groupPosition).memberEntities.size();  
  53.     }  
  54.   
  55.     @Override  
  56.     public Object getGroup(int groupPosition) {  
  57.         // TODO Auto-generated method stub  
  58.         return mGroupEntities.get(groupPosition);  
  59.     }  
  60.   
  61.     @Override  
  62.     public int getGroupCount() {  
  63.         // TODO Auto-generated method stub  
  64.         return mGroupEntities.size();  
  65.     }  
  66.   
  67.     @Override  
  68.     public long getGroupId(int groupPosition) {  
  69.         // TODO Auto-generated method stub  
  70.         return groupPosition;  
  71.     }  
  72.   
  73.     @Override  
  74.     public View getGroupView(int groupPosition, boolean isExpanded,  
  75.             View convertView, ViewGroup parent) {  
  76.         if (convertView == null) {  
  77.             convertView =  mInflater.inflate(R.layout.item_group_content, parent, false);  
  78.         }  
  79.         TextView text_group_cotent = ViewHolder.get(convertView, R.id.text_group_content);  
  80.         GroupEntity entity = (GroupEntity)getGroup(groupPosition);  
  81.         text_group_cotent.setText(entity.groupName);  
  82.         return convertView;  
  83.     }  
  84.   
  85.     @Override  
  86.     public boolean hasStableIds() {  
  87.         // TODO Auto-generated method stub  
  88.         return true;  
  89.     }  
  90.   
  91.     @Override  
  92.     public boolean isChildSelectable(int groupPosition, int childPosition) {  
  93.         // TODO Auto-generated method stub  
  94.         return true;  
  95.     }  
  96.   
  97. }  
  所以,当在MainActivity中通过调用parseToBean方法完成解析xml数据后,将解析得到的实体类填充到适配器中,然后通过ExpandableListView显示出来。工程中的ViewHolder是自定义类,它的存在,是为了避免在Adapter类中频繁地创建ViewHolder。

 7.ViewHolder.java文件代码如下:

[java] view plain copy
  1. package com.steven.android.sax.xml.custom;  
  2.   
  3. import android.util.SparseArray;  
  4. import android.view.View;  
  5.   
  6. public class ViewHolder {  
  7.     @SuppressWarnings("unchecked")  
  8.     public static extends View> T get(View view, int id) {  
  9.         SparseArray viewHolder = (SparseArray) view.getTag();  
  10.         if (viewHolder == null) {  
  11.             viewHolder = new SparseArray();  
  12.             view.setTag(viewHolder);  
  13.         }  
  14.         View childView = viewHolder.get(id);  
  15.         if (childView == null) {  
  16.             childView = view.findViewById(id);  
  17.             viewHolder.put(id, childView);  
  18.         }  
  19.         return (T) childView;  
  20.     }  
  21. }  

  

 二、SAX解析xml格式数据。

  前面介绍了如何借助simple-xml包解析xml数据。这里,将要介绍不需要通过第三方jar包,如何通过SAX有效地去解析xml数据。关于SAX的介绍,笔者在这里就不再累赘了,相信很多程序猿都接触过了。

   下面是整个Demo工程文件截图,如下图:

Android学习系列(19)-App数据格式之解析Xml_第2张图片

 
  该工程代码和simple-xml工程代码一样,也是将解析的xml数据通过ExpandableListView显示出来。assets目录中的data.xml文件内容、ExpandAdapter类、相关文件布局和simple-xml工程差不多都是一样的,这里就不贴出来了。不过实体类是有变化的, 不再是公共成员变量形式存在,而是私有变量形式存在,以set、get形式赋值和取值。下面看看实体类的代码。

   1.GroupEntity.java文件代码如下:

[java] view plain copy
  1. package com.steven.android.sax.xml.entity;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5.   
  6. public class GroupEntity {  
  7.     private String groupId;  
  8.     private String groupName;  
  9.     private List memberEntities = new ArrayList();;  
  10.   
  11.     public String getGroupId() {  
  12.         return groupId;  
  13.     }  
  14.   
  15.     public void setGroupId(String groupId) {  
  16.         this.groupId = groupId;  
  17.     }  
  18.   
  19.     public String getGroupName() {  
  20.         return groupName;  
  21.     }  
  22.   
  23.     public void setGroupName(String groupName) {  
  24.         this.groupName = groupName;  
  25.     }  
  26.   
  27.     public List getMemberEntities() {  
  28.         return memberEntities;  
  29.     }  
  30.   
  31.     public void setMemberEntities(List memberEntities) {  
  32.         this.memberEntities = memberEntities;  
  33.     }  
  34.   
  35. }  
   2.MemberEntity.java文件代码如下:

[java] view plain copy
  1. package com.steven.android.sax.xml.entity;  
  2.   
  3. public class MemberEntity {  
  4.   
  5.     private String name;  
  6.     private String age;  
  7.   
  8.     public String getName() {  
  9.         return name;  
  10.     }  
  11.   
  12.     public void setName(String name) {  
  13.         this.name = name;  
  14.     }  
  15.   
  16.     public String getAge() {  
  17.         return age;  
  18.     }  
  19.   
  20.     public void setAge(String age) {  
  21.         this.age = age;  
  22.     }  
  23.   
  24. }  
   接下来,我们看看主页面的代码。

  3.MainActivity.java文件代码如下:

[java] view plain copy
  1. package com.steven.android.sax.xml.activity;  
  2.   
  3. import java.io.BufferedReader;  
  4. import java.io.IOException;  
  5. import java.io.InputStream;  
  6. import java.io.InputStreamReader;  
  7. import java.util.List;  
  8. import java.util.regex.Matcher;  
  9. import java.util.regex.Pattern;  
  10. import android.app.Activity;  
  11. import android.os.Bundle;  
  12. import android.text.TextUtils;  
  13. import android.view.Menu;  
  14. import android.widget.ExpandableListView;  
  15. import com.steven.android.sax.xml.adapter.ExpandAdapter;  
  16. import com.steven.android.sax.xml.entity.GroupEntity;  
  17. import com.steven.android.sax.xml.handler.DataParseHandler;  
  18. import com.steven.android.sax.xml.util.XmlParserUtil;  
  19. /** 
  20.  * 描述:主页面 
  21.  * @author stevenhu223 
  22.  * 
  23.  */  
  24. public class MainActivity extends Activity {  
  25.       
  26.     private ExpandableListView mExpandableListView;  
  27.     private ExpandAdapter mAdapter;  
  28.       
  29.     @Override  
  30.     protected void onCreate(Bundle savedInstanceState) {  
  31.         super.onCreate(savedInstanceState);  
  32.         setContentView(R.layout.activity_main);  
  33.         mExpandableListView = (ExpandableListView) findViewById(R.id.expanlist_content);  
  34.         try {  
  35.             matchAndParseXmlData();  
  36.         } catch (Exception e) {  
  37.             // TODO Auto-generated catch block  
  38.             e.printStackTrace();  
  39.         }  
  40.     }  
  41.   
  42.     @Override  
  43.     public boolean onCreateOptionsMenu(Menu menu) {  
  44.         // Inflate the menu; this adds items to the action bar if it is present.  
  45.         getMenuInflater().inflate(R.menu.main, menu);  
  46.         return true;  
  47.     }  
  48.   
  49.     /** 
  50.      * 匹配获取和解析xml文件内容 
  51.      * @throws Exception 
  52.      */  
  53.     private void matchAndParseXmlData() throws Exception {  
  54.         InputStream inputStream = getResources().getAssets().open("data.xml");  
  55.         String dataContent = convertStreamToString(inputStream);  
  56.         String content = "";  
  57.         Pattern DATA_PATTERN= Pattern.compile("[\\S\\s]*([\\s\\S]*)[\\s\\S]*");  
  58.         Matcher matcher = DATA_PATTERN.matcher(dataContent);  
  59.         if (matcher.matches()) {  
  60.             content = matcher.group(1);  
  61.         }   
  62.         if (!TextUtils.isEmpty(content)) {  
  63.             DataParseHandler handler = new DataParseHandler();  
  64.             XmlParserUtil.parserXMLByHandler(handler, content);  
  65.             List mGroupEntities = handler.getResult();  
  66.             mAdapter = new ExpandAdapter(this, mGroupEntities);  
  67.             mExpandableListView.setAdapter(mAdapter);  
  68.         }  
  69.     }  
  70.       
  71.     /** 
  72.      * 输入流转字符串 
  73.      * @param is 
  74.      * @return 
  75.      */  
  76.     public String convertStreamToString(InputStream is) {  
  77.   
  78.         BufferedReader reader = new BufferedReader(new InputStreamReader(is));  
  79.         StringBuilder sb = new StringBuilder();  
  80.         String line = null;  
  81.         try {  
  82.             while ((line = reader.readLine()) != null) {  
  83.                 sb.append(line);  
  84.             }  
  85.         } catch (IOException e) {  
  86.             e.printStackTrace();  
  87.         } finally {  
  88.             try {  
  89.                 is.close();  
  90.             } catch (IOException e) {  
  91.                 e.printStackTrace();  
  92.             }  
  93.         }  
  94.         return sb.toString();  
  95.   
  96.     }  
  97.       
  98. }  
  在MainActivity中,matchAndParseData方法实现SAX解析xml数据。SAX解析xml数据,其实重点是如何创建继承DefaultHandler2的类。我们来看看工程中创建的DataParseHandler类。

  4.DataParseHandler.java文件代码如下:

[java] view plain copy
  1. package com.steven.android.sax.xml.handler;  
  2.   
  3. import java.util.ArrayList;  
  4. import org.xml.sax.Attributes;  
  5. import org.xml.sax.InputSource;  
  6. import org.xml.sax.SAXException;  
  7. import org.xml.sax.ext.DefaultHandler2;  
  8. import com.steven.android.sax.xml.entity.GroupEntity;  
  9. import com.steven.android.sax.xml.entity.MemberEntity;  
  10.   
  11. /** 
  12.  * 描述:data.xml文件内容解析handler
     
  13.  *  
  14.  * @author stevenhu223 
  15.  */  
  16. public class DataParseHandler extends DefaultHandler2 {  
  17.   
  18.     InputSource mInputSource;  
  19.     String nodeName;  
  20.     public GroupEntity groupEntity;  
  21.     public MemberEntity memberEntity;  
  22.     public ArrayList groupEntities;  
  23.   
  24.     StringBuffer cData;// 某一段cdata的值  
  25.   
  26.     public DataParseHandler() {  
  27.         cData = new StringBuffer();  
  28.         groupEntities = new ArrayList();  
  29.     }  
  30.   
  31.     @Override  
  32.     public void characters(char[] ch, int start, int length)  
  33.             throws SAXException {  
  34.   
  35.         if (nodeName != null && nodeName.equals("groupID")) {  
  36.             String data = new String(ch, start, length);  
  37.             cData.append(data);  
  38.             super.characters(ch, start, length);  
  39.         } else if (nodeName != null && nodeName.equals("groupName")) {  
  40.             String data = new String(ch, start, length);  
  41.             cData.append(data);  
  42.             super.characters(ch, start, length);  
  43.         } else if (nodeName != null && nodeName.equals("name")) {  
  44.             String data = new String(ch, start, length);  
  45.             cData.append(data);  
  46.             super.characters(ch, start, length);  
  47.         } else if (nodeName != null && nodeName.equals("age")) {  
  48.             String data = new String(ch, start, length);  
  49.             cData.append(data);  
  50.             super.characters(ch, start, length);  
  51.         }  
  52.     }  
  53.   
  54.     @Override  
  55.     public void startElement(String uri, String localName, String name,  
  56.             Attributes atts) throws SAXException {  
  57.         nodeName = localName;  
  58.         if (localName.equals("group")) {  
  59.             //读到group开始元素时创建GroupEntity对象  
  60.             groupEntity = new GroupEntity();  
  61.         } else if (localName.equals("member")){  
  62.             //读到member开始元素时创建MemberEntity对象  
  63.             memberEntity = new MemberEntity();  
  64.         } else if (localName.equals("groupID")) {  
  65.             startCDATA();  
  66.         } else if (localName.equals("groupName")) {  
  67.             startCDATA();  
  68.         } else if (localName.equals("name")) {  
  69.             startCDATA();  
  70.         } else if (localName.equals("age")) {  
  71.             startCDATA();  
  72.         }   
  73.   
  74.     }  
  75.   
  76.     @Override  
  77.     public void endElement(String uri, String localName, String name)  
  78.             throws SAXException {  
  79.         nodeName = null;  
  80.         if (localName.equals("group")) {  
  81.             //读到group结束元素时添加GroupEntity对象添加到集合  
  82.             groupEntities.add(groupEntity);  
  83.         } else if (localName.equals("member")) {  
  84.             //读到member结束元素时将MemberEntity对象添加到集合  
  85.             groupEntity.getMemberEntities().add(memberEntity);  
  86.         } else if (localName.equals("groupID")) {  
  87.             endCDATA();  
  88.             groupEntity.setGroupId(getCDataString());  
  89.         } else if (localName.equals("groupName")) {  
  90.             endCDATA();  
  91.             groupEntity.setGroupName(getCDataString());  
  92.         } else if (localName.equals("name")) {  
  93.             endCDATA();  
  94.             memberEntity.setName(getCDataString());  
  95.         } else if (localName.equals("age")) {  
  96.             endCDATA();  
  97.             memberEntity.setAge(getCDataString());  
  98.         }   
  99.     }  
  100.   
  101.     private String getCDataString() {  
  102.         return cData.toString();  
  103.     }  
  104.   
  105.     // 重新开始CDATA  
  106.     @Override  
  107.     public void startCDATA() throws SAXException {  
  108.         if (cData == null) {  
  109.             cData = new StringBuffer();  
  110.         } else {  
  111.             cData.delete(0, cData.length());  
  112.         }  
  113.         super.startCDATA();  
  114.     }  
  115.   
  116.     @Override  
  117.     public void endCDATA() throws SAXException {  
  118.   
  119.         super.endCDATA();  
  120.     }  
  121.   
  122.     public ArrayList getResult() {  
  123.         return groupEntities;  
  124.     }  
  125.   
  126. }  
   通过 DataParseHandler的getResult()方法可以获取到解析xml数据成功后的实体集合。在创xml解析数据对应的DataParseHandler类后,还需要将该类的对象和需要解析的xml数据关联起来,于是就有了XmlParserUtil工具类。

  5.XmlParserUtil.java文件代码如下:

[java] view plain copy
  1. package com.steven.android.sax.xml.util;  
  2.   
  3. import java.io.StringReader;  
  4.   
  5. import javax.xml.parsers.SAXParserFactory;  
  6. import org.xml.sax.InputSource;  
  7. import org.xml.sax.XMLReader;  
  8. import org.xml.sax.ext.DefaultHandler2;  
  9. /** 
  10.  *  描述:Sax解析工具类 
  11.  * @author stevenhu223 
  12.  * 
  13.  */  
  14. public class XmlParserUtil {  
  15.   
  16.     /** 
  17.      * 关联DefaultHandler2和xml数据进行解析 
  18.      * @param handler 
  19.      * @param xml 
  20.      */  
  21.     public static void parserXMLByHandler(DefaultHandler2 handler,String xml) {  
  22.         XMLReader xmlReader;  
  23.         InputSource input = getInputSouceByString(xml);  
  24.         try {  
  25.             SAXParserFactory s = SAXParserFactory.newInstance();  
  26.             xmlReader = s.newSAXParser().getXMLReader();  
  27.             xmlReader.setContentHandler(handler);  
  28.             xmlReader.parse(input);  
  29.   
  30.         } catch (Exception e) {  
  31.   
  32.             e.printStackTrace();  
  33.         }  
  34.     }  
  35.       
  36.     /** 
  37.      * 通过字符串获取流 
  38.      * @param xmlStr 
  39.      * @return 
  40.      */  
  41.     public static InputSource getInputSouceByString(String xmlStr) {  
  42.         StringReader sr = new StringReader(xmlStr);  
  43.         InputSource is = new InputSource(sr);  
  44.         return is;  
  45.   
  46.     }  
  47.       
  48. }  

 所以,通过创建对应的DataParseHandler与XmlParserUtil关联起来就可以完成解析xml数据了。

 小结:关于SAX解析xml数据。比较麻烦的是,每份需要解析的xml数据对应的都需要创建相应的DefaultHandler2类,如果App后台接口较多的话,需要创建的解析后台数据的DefaultHandler2类也就相应的增多,这样会给App的维护带来一定的弊端。这种情况下建议还是使用simple-xml解析,毕竟simple-xml包也不大,也就418KB而已。笔者就经常使用simple-xml包解析xml数据。

   

    三、jackson包解析json格式数据

   上面讲解的是xml数据解析,接下来将谈谈json数据的解析,json数据的解析有很多种方式。当然,我个人比较喜欢的是jackson包对Json数据的解析,jackson包相对来说比较大一点,有1MB以上,不过速度快,效率高,性能72个赞。这个就是笔者比较青睐它的原因。当然了,有时候考虑到工程的大小,也不得不考虑其他方式的解析,google也提供了一些json解析的工具包,这里也不再一一介绍,有兴趣可以去google官网去了解了解。这里主要还是介绍jackson的解析,不喜欢的可以绕道绕道咯。jackson的官网地址为:http://jackson.codehaus.org/,相关的jar包可以到官网上下载。

    下面是整个Demo工程文件截图,如下图:

Android学习系列(19)-App数据格式之解析Xml_第3张图片

     同样的,该工程也是在simple-xml工程的基础上去做处理,也是将解析后的数据通过ExpandableListView显示出来。相同的类,这里就不在贴出来了。不过相关的实体类会有变化。assets目录中的jsonData文件内容为json格式。内容和simple-xml工程中的data.xml文件内容一样,只不过是json格式,我们来看看jsonData文件内容。

   1.jsonData文件内容如下(注意:将jsonData文件的编码格式设置为UTF-8,否则文件将出现乱编吗):

[plain] view plain copy
  1. {  
  2.   "dataContent": {  
  3.     "group": [  
  4.       {  
  5.         "groupID": "1",  
  6.         "groupName": "第一组",  
  7.         "member": [  
  8.           {  
  9.             "name": "张三",  
  10.             "age": "22"  
  11.           },  
  12.           {  
  13.             "name": "李四",  
  14.             "age": "24"  
  15.           },  
  16.           {  
  17.             "name": "欧阳雪",  
  18.             "age": "18"  
  19.           }  
  20.         ]  
  21.       },  
  22.       {  
  23.         "groupID": "2",  
  24.         "groupName": "第二组",  
  25.         "member": [  
  26.           {  
  27.             "name": "司徒静",  
  28.             "age": "19"  
  29.           },  
  30.           {  
  31.             "name": "叶笙",  
  32.             "age": "26"  
  33.           },  
  34.           {  
  35.             "name": "杨风",  
  36.             "age": "25"  
  37.           }  
  38.         ]  
  39.       },  
  40.       {  
  41.         "groupID": "3",  
  42.         "groupName": "第三组",  
  43.         "member": [  
  44.           {  
  45.             "name": "王龙",  
  46.             "age": "32"  
  47.           },  
  48.           {  
  49.             "name": "西门胜男",  
  50.             "age": "21"  
  51.           },  
  52.           {  
  53.             "name": "张铬",  
  54.             "age": "45"  
  55.           }  
  56.         ]  
  57.       }  
  58.     ]  
  59.   }  
  60. }  

   接下来,我们看看主页面的代码。

   2.MainActivity.java文件代码如下:

[java] view plain copy
  1. package com.steven.android.jackson.activity;  
  2.   
  3. import java.io.BufferedReader;  
  4. import java.io.IOException;  
  5. import java.io.InputStream;  
  6. import java.io.InputStreamReader;  
  7. import org.codehaus.jackson.map.ObjectMapper;  
  8. import org.codehaus.jackson.type.TypeReference;  
  9. import android.app.Activity;  
  10. import android.os.Bundle;  
  11. import android.view.Menu;  
  12. import android.widget.ExpandableListView;  
  13. import com.steven.android.jackson.adapter.ExpandAdapter;  
  14. import com.steven.android.jackson.entity.JsonResponseEntity;  
  15. /** 
  16.  * 描述:主页面 
  17.  * @author stevenhu223 
  18.  * 
  19.  */  
  20. public class MainActivity extends Activity {  
  21.       
  22.     private ExpandableListView mExpandableListView;  
  23.     private ExpandAdapter mAdapter;  
  24.     private ObjectMapper mObjectMapper;  
  25.       
  26.     @Override  
  27.     protected void onCreate(Bundle savedInstanceState) {  
  28.         super.onCreate(savedInstanceState);  
  29.         setContentView(R.layout.activity_main);  
  30.         mExpandableListView = (ExpandableListView) findViewById(R.id.expanlist_content);  
  31.         mObjectMapper = new ObjectMapper();  
  32.         try {  
  33.             parseJsonData();  
  34.         } catch (Exception e) {  
  35.             // TODO Auto-generated catch block  
  36.             e.printStackTrace();  
  37.         }  
  38.     }  
  39.   
  40.     @Override  
  41.     public boolean onCreateOptionsMenu(Menu menu) {  
  42.         // Inflate the menu; this adds items to the action bar if it is present.  
  43.         getMenuInflater().inflate(R.menu.main, menu);  
  44.         return true;  
  45.     }  
  46.   
  47.     /** 
  48.      * json数据格式解析 
  49.      * @throws Exception 
  50.      */  
  51.     private void parseJsonData()  throws Exception{  
  52.         InputStream inputStream = getResources().getAssets().open("jsonData");  
  53.         String dataContent = convertStreamToString(inputStream);  
  54.         try {  
  55.             JsonResponseEntity datEntity = mObjectMapper.readValue(dataContent,  
  56.                     new TypeReference() {  
  57.                     });  
  58.             mAdapter = new ExpandAdapter(this, datEntity.getDataContent().getGroup());  
  59.             mExpandableListView.setAdapter(mAdapter);  
  60.         } catch (Exception e) {  
  61.             // TODO: handle exception  
  62.             e.printStackTrace();  
  63.         }  
  64.     }  
  65.       
  66.     /** 
  67.      * 输入流转字符串 
  68.      * @param is 
  69.      * @return 
  70.      */  
  71.     public String convertStreamToString(InputStream is) {  
  72.   
  73.         BufferedReader reader = new BufferedReader(new InputStreamReader(is));  
  74.         StringBuilder sb = new StringBuilder();  
  75.         String line = null;  
  76.         try {  
  77.             while ((line = reader.readLine()) != null) {  
  78.                 sb.append(line);  
  79.             }  
  80.         } catch (IOException e) {  
  81.             e.printStackTrace();  
  82.         } finally {  
  83.             try {  
  84.                 is.close();  
  85.             } catch (IOException e) {  
  86.                 e.printStackTrace();  
  87.             }  
  88.         }  
  89.         return sb.toString();  
  90.   
  91.     }  
  92.       
  93. }  
  代码中,parseJsonData方法实现jackson解析json格式数据,ObjectMapper来自jackson包,通过调用mObjectMapper对象readValue函数就可以实现对json数据的解析。我们来看看JsonResponseEntity实体类的代码。

  3.JsonResponseEntity.java文件代码如下:

[java] view plain copy
  1. package com.steven.android.jackson.entity;  
  2.   
  3. public class JsonResponseEntity {  
  4.   
  5.     /** 
  6.      * jackson解析有严格的规定,变量名要和对应的元素名一致,否则解析会时会报错 
  7.      */  
  8.     private DataContentEntity dataContent;  
  9.   
  10.     public DataContentEntity getDataContent() {  
  11.         return dataContent;  
  12.     }  
  13.   
  14.     public void setDataContent(DataContentEntity dataContent) {  
  15.         this.dataContent = dataContent;  
  16.     }  
  17.       
  18. }  
  值得注意的是,jackson解析有严格的实体类变量名对应json数据中的key名相同的限制,如果不一致,解析将会有问题。变量名dataContent对应的就是jsonData文件内容中的第一个key(dataContent);接下来来列出的其他实体类中的变量名,集合名都要和jsonData文件内容中的一致。
  4.DataContentEntity.java文件代码如下:

[java] view plain copy
  1. package com.steven.android.jackson.entity;  
  2.   
  3. import java.util.List;  
  4.   
  5. public class DataContentEntity {  
  6.   
  7.     //变量名对应json内容中的group  
  8.     private List group;  
  9.   
  10.     public List getGroup() {  
  11.         return group;  
  12.     }  
  13.   
  14.     public void setGroup(List group) {  
  15.         this.group = group;  
  16.     }  
  17. }  
  5.GroupEntity文件代码如下:

[java] view plain copy
  1. package com.steven.android.jackson.entity;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5.   
  6. public class GroupEntity {  
  7.       
  8.     private String groupID; //变量名对应json内容中的groupID  
  9.     private String groupName; //变量名对应json内容中的groupName  
  10.     //变量名对应json内容中的member  
  11.     private List member = new ArrayList();  
  12.   
  13.     public String getGroupID() {  
  14.         return groupID;  
  15.     }  
  16.   
  17.     public void setGroupID(String groupID) {  
  18.         this.groupID = groupID;  
  19.     }  
  20.   
  21.     public String getGroupName() {  
  22.         return groupName;  
  23.     }  
  24.   
  25.     public void setGroupName(String groupName) {  
  26.         this.groupName = groupName;  
  27.     }  
  28.   
  29.     public List getMember() {  
  30.         return member;  
  31.     }  
  32.   
  33.     public void setMember(List member) {  
  34.         this.member = member;  
  35.     }  
  36.   
  37. }  
  6.MemberEntity.java文件代码如下:
[java] view plain copy
  1. package com.steven.android.jackson.entity;  
  2.   
  3. public class MemberEntity {  
  4.   
  5.     private String name; //变量名对应json内容中的name  
  6.     private String age; //变量名对应json内容中的age  
  7.   
  8.     public String getName() {  
  9.         return name;  
  10.     }  
  11.   
  12.     public void setName(String name) {  
  13.         this.name = name;  
  14.     }  
  15.   
  16.     public String getAge() {  
  17.         return age;  
  18.     }  
  19.   
  20.     public void setAge(String age) {  
  21.         this.age = age;  
  22.     }  
  23.   
  24. }  
  以上为jackson解析相关的实体类。通过MainActivity的parseJson方法就可以将json数据解析成封装的DataJsonResponseEntity了。

你可能感兴趣的:(Android学习系列)