Android中的xml、json格式数据解析

            转载请注明出处: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中的xml、json格式数据解析_第1张图片

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

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

<?xml version="1.0" encoding="utf-8"?>
<resources>
<?xml version="1.0" encoding="utf-8"?>
    <dataContent>
        <group>
            <groupID>1</groupID>
            <groupName>第一组</groupName>
            <member>
                <name>张三</name>
                <age>22</age>
            </member>
            <member>
                <name>李四</name>
                <age>24</age>
            </member>
            <member>
                <name>欧阳雪</name>
                <age>18</age>
            </member>
        </group>
        <group>
            <groupID>2</groupID>
            <groupName>第二组</groupName>
            <member>
                <name>司徒静</name>
                <age>19</age>
            </member>
            <member>
                <name>叶笙</name>
                <age>26</age>
            </member>
            <member>
                <name>杨风</name>
                <age>25</age>
            </member>
        </group>
        <group>
            <groupID>3</groupID>
            <groupName>第三组</groupName>
            <member>
                <name>王龙</name>
                <age>32</age>
            </member>
            <member>
                <name>西门胜男</name>
                <age>21</age>
            </member>
            <member>
                <name>张铬</name>
                <age>45</age>
            </member>
        </group>
    </dataContent>

</resources>
   通过上面的文件内容,我们知道,这个文件内容主要有三组数据,每组数据有个三个成员组,每个成员组都有名字和年龄这两个子元素。Demo中将这些解析出来内容通过ExpandableListView显示出来。

  2.主页面MainActivity代码如下:

package com.steven.android.simple.xml.activity;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.simpleframework.xml.core.Persister;
import android.app.Activity;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.Menu;
import android.widget.ExpandableListView;
import com.steven.android.simple.xml.adapter.ExpandAdapter;
import com.steven.android.simple.xml.parse.DataParseResponse;
/**
 * 描述:主页面
 * @author stevenhu223
 *
 */
public class MainActivity extends Activity {

	private  final String TAG = "MainActivity";
	private ExpandableListView mExpandableListView;
	private ExpandAdapter mAdapter;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		mExpandableListView = (ExpandableListView) findViewById(R.id.expanlist_content);
		try {
			matchAndParseData();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

	/**
	 * 匹配获取和解析xml文件内容
	 * @throws Exception
	 */
	private void matchAndParseData() throws Exception {
		InputStream inputStream = getResources().getAssets().open("data.xml");
		String dataContent = convertStreamToString(inputStream);
		String content = "";
		//正则表达式匹配
		Pattern DATA_PATTERN= Pattern.compile("[\\S\\s]*(<dataContent>[\\s\\S]*</dataContent>)[\\s\\S]*");
		Matcher matcher = DATA_PATTERN.matcher(dataContent);
		if (matcher.matches()) {
			//获取包含dataContent元素的内容
			content = matcher.group(1);
		} 
		if (!TextUtils.isEmpty(content)) {
			DataParseResponse dataResponse = parseToBean(DataParseResponse.class, content);
			mAdapter = new ExpandAdapter(this, dataResponse.mGroupEntities);
			mExpandableListView.setAdapter(mAdapter);
		}
	}

	/**
	 * 将xml文件内容解析成实体类
	 * @param type
	 * @param data
	 * @return
	 */
	private <T> T parseToBean(Class<T> type , String data) {

        try {
            return new Persister().read(type, data, false);
        } catch (Exception e) {
            Log.e(TAG, "parse Data error", e);
            throw new RuntimeException(e);
        }
	
	}
	
	/**
	 * 输入流转字符串
	 * @param is
	 * @return
	 */
	public String convertStreamToString(InputStream is) {

		BufferedReader reader = new BufferedReader(new InputStreamReader(is));
		StringBuilder sb = new StringBuilder();
		String line = null;
		try {
			while ((line = reader.readLine()) != null) {
				sb.append(line);
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				is.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return sb.toString();

	}
}
  上面的代码中,parseToBean方法的功能就是将xml格式数据解析成对应的实体类,Persister类是simple-xml包中的类。通过调用parseToBean函数将xml内容数据解析封装成DataParseResponse对象,接下来我们看看DataParseResponse的代码。

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

package com.steven.android.simple.xml.parse;

import org.simpleframework.xml.ElementList;
import org.simpleframework.xml.Root;

import com.steven.android.simple.xml.entity.GroupEntity;

import java.util.List;

/**
 *  描述:解析数据响应类
 * 此处的dataContent要对应xml文件中的dataContent元素
 * @author stenvenhu223
 *
 */
@Root(name = "dataContent")
public class DataParseResponse {
	@ElementList(inline=true,required=false)
	public List<GroupEntity> mGroupEntities;
}
  通过上面的代码我们知道,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文件代码如下:

package com.steven.android.simple.xml.entity;

import java.util.List;

import org.simpleframework.xml.Element;
import org.simpleframework.xml.ElementList;
import org.simpleframework.xml.Root;
@Root(name="group")
public class GroupEntity {
	@Element(name="groupID") public String groupId;
	@Element(name="groupName") public String groupName;
	@ElementList(inline=true,required=false)
	public List<MemberEntity> memberEntities;
	
}
   代码中,@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文件代码如下:

@Root(name="member")
public class MemberEntity {
	@Element(required=false) public String name;
	@Element(required=false) public String age;
}
   MemberEntity代码中的代码注释这里就不多说了,原理和其他的实体类是一致的。

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

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

package com.steven.android.simple.xml.adapter;

import java.util.List;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.TextView;
import com.steven.android.simple.xml.activity.R;
import com.steven.android.simple.xml.custom.ViewHolder;
import com.steven.android.simple.xml.entity.GroupEntity;
import com.steven.android.simple.xml.entity.MemberEntity;

public class ExpandAdapter extends BaseExpandableListAdapter{

	private List<GroupEntity> mGroupEntities;
	private LayoutInflater mInflater;
	
	public  ExpandAdapter(Context context, List<GroupEntity> list) {
		mGroupEntities = list;
		mInflater = LayoutInflater.from(context);
	}
	
	@Override
	public Object getChild(int groupPosition, int childPosition) {
		// TODO Auto-generated method stub
		return mGroupEntities.get(groupPosition).memberEntities.get(childPosition);
	}

	@Override
	public long getChildId(int groupPosition, int childPosition) {
		// TODO Auto-generated method stub
		return childPosition;
	}

	@Override
	public View getChildView(int groupPosition, int childPosition,
			boolean isLastChild, View convertView, ViewGroup parent) {
		if (convertView == null) {
			convertView = mInflater.inflate(R.layout.item_member_content, parent, false);
		}
		TextView text_member_content = ViewHolder.get(convertView, R.id.text_member_content);
		MemberEntity entity = (MemberEntity)getChild(groupPosition, childPosition);
		text_member_content.setText(entity.name);
		return convertView;
	}

	@Override
	public int getChildrenCount(int groupPosition) {
		// TODO Auto-generated method stub
		return mGroupEntities.get(groupPosition).memberEntities.size();
	}

	@Override
	public Object getGroup(int groupPosition) {
		// TODO Auto-generated method stub
		return mGroupEntities.get(groupPosition);
	}

	@Override
	public int getGroupCount() {
		// TODO Auto-generated method stub
		return mGroupEntities.size();
	}

	@Override
	public long getGroupId(int groupPosition) {
		// TODO Auto-generated method stub
		return groupPosition;
	}

	@Override
	public View getGroupView(int groupPosition, boolean isExpanded,
			View convertView, ViewGroup parent) {
		if (convertView == null) {
			convertView =  mInflater.inflate(R.layout.item_group_content, parent, false);
		}
		TextView text_group_cotent = ViewHolder.get(convertView, R.id.text_group_content);
		GroupEntity entity = (GroupEntity)getGroup(groupPosition);
		text_group_cotent.setText(entity.groupName);
		return convertView;
	}

	@Override
	public boolean hasStableIds() {
		// TODO Auto-generated method stub
		return true;
	}

	@Override
	public boolean isChildSelectable(int groupPosition, int childPosition) {
		// TODO Auto-generated method stub
		return true;
	}

}
  所以,当在MainActivity中通过调用parseToBean方法完成解析xml数据后,将解析得到的实体类填充到适配器中,然后通过ExpandableListView显示出来。工程中的ViewHolder是自定义类,它的存在,是为了避免在Adapter类中频繁地创建ViewHolder。

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

package com.steven.android.sax.xml.custom;

import android.util.SparseArray;
import android.view.View;

public class ViewHolder {
	@SuppressWarnings("unchecked")
	public static <T extends View> T get(View view, int id) {
		SparseArray<View> viewHolder = (SparseArray<View>) view.getTag();
		if (viewHolder == null) {
			viewHolder = new SparseArray<View>();
			view.setTag(viewHolder);
		}
		View childView = viewHolder.get(id);
		if (childView == null) {
			childView = view.findViewById(id);
			viewHolder.put(id, childView);
		}
		return (T) childView;
	}
}

  

 二。SAX解析xml格式数据。

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

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

Android中的xml、json格式数据解析_第2张图片

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

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

package com.steven.android.sax.xml.entity;

import java.util.ArrayList;
import java.util.List;

public class GroupEntity {
	private String groupId;
	private String groupName;
	private List<MemberEntity> memberEntities = new ArrayList<MemberEntity>();;

	public String getGroupId() {
		return groupId;
	}

	public void setGroupId(String groupId) {
		this.groupId = groupId;
	}

	public String getGroupName() {
		return groupName;
	}

	public void setGroupName(String groupName) {
		this.groupName = groupName;
	}

	public List<MemberEntity> getMemberEntities() {
		return memberEntities;
	}

	public void setMemberEntities(List<MemberEntity> memberEntities) {
		this.memberEntities = memberEntities;
	}

}
   2.MemberEntity.java文件代码如下:

package com.steven.android.sax.xml.entity;

public class MemberEntity {

	private String name;
	private String age;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getAge() {
		return age;
	}

	public void setAge(String age) {
		this.age = age;
	}

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

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

package com.steven.android.sax.xml.activity;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import android.app.Activity;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.Menu;
import android.widget.ExpandableListView;
import com.steven.android.sax.xml.adapter.ExpandAdapter;
import com.steven.android.sax.xml.entity.GroupEntity;
import com.steven.android.sax.xml.handler.DataParseHandler;
import com.steven.android.sax.xml.util.XmlParserUtil;
/**
 * 描述:主页面
 * @author stevenhu223
 *
 */
public class MainActivity extends Activity {
	
	private ExpandableListView mExpandableListView;
	private ExpandAdapter mAdapter;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		mExpandableListView = (ExpandableListView) findViewById(R.id.expanlist_content);
		try {
			matchAndParseXmlData();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

	/**
	 * 匹配获取和解析xml文件内容
	 * @throws Exception
	 */
	private void matchAndParseXmlData() throws Exception {
		InputStream inputStream = getResources().getAssets().open("data.xml");
		String dataContent = convertStreamToString(inputStream);
		String content = "";
		Pattern DATA_PATTERN= Pattern.compile("[\\S\\s]*(<dataContent>[\\s\\S]*</dataContent>)[\\s\\S]*");
		Matcher matcher = DATA_PATTERN.matcher(dataContent);
		if (matcher.matches()) {
			content = matcher.group(1);
		} 
		if (!TextUtils.isEmpty(content)) {
			DataParseHandler handler = new DataParseHandler();
			XmlParserUtil.parserXMLByHandler(handler, content);
			List<GroupEntity> mGroupEntities = handler.getResult();
			mAdapter = new ExpandAdapter(this, mGroupEntities);
			mExpandableListView.setAdapter(mAdapter);
		}
	}
	
	/**
	 * 输入流转字符串
	 * @param is
	 * @return
	 */
	public String convertStreamToString(InputStream is) {

		BufferedReader reader = new BufferedReader(new InputStreamReader(is));
		StringBuilder sb = new StringBuilder();
		String line = null;
		try {
			while ((line = reader.readLine()) != null) {
				sb.append(line);
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				is.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return sb.toString();

	}
	
}
  在MainActivity中,matchAndParseData方法实现SAX解析xml数据。SAX解析xml数据,其实重点是如何创建继承DefaultHandler2的类。我们来看看工程中创建的DataParseHandler类。

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

package com.steven.android.sax.xml.handler;

import java.util.ArrayList;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.ext.DefaultHandler2;
import com.steven.android.sax.xml.entity.GroupEntity;
import com.steven.android.sax.xml.entity.MemberEntity;

/**
 * 描述:data.xml文件内容解析handler</br>
 * 
 * @author stevenhu223
 */
public class DataParseHandler extends DefaultHandler2 {

	InputSource mInputSource;
	String nodeName;
	public GroupEntity groupEntity;
	public MemberEntity memberEntity;
	public ArrayList<GroupEntity> groupEntities;

	StringBuffer cData;// 某一段cdata的值

	public DataParseHandler() {
		cData = new StringBuffer();
		groupEntities = new ArrayList<GroupEntity>();
	}

	@Override
	public void characters(char[] ch, int start, int length)
			throws SAXException {

		if (nodeName != null && nodeName.equals("groupID")) {
			String data = new String(ch, start, length);
			cData.append(data);
			super.characters(ch, start, length);
		} else if (nodeName != null && nodeName.equals("groupName")) {
			String data = new String(ch, start, length);
			cData.append(data);
			super.characters(ch, start, length);
		} else if (nodeName != null && nodeName.equals("name")) {
			String data = new String(ch, start, length);
			cData.append(data);
			super.characters(ch, start, length);
		} else if (nodeName != null && nodeName.equals("age")) {
			String data = new String(ch, start, length);
			cData.append(data);
			super.characters(ch, start, length);
		}
	}

	@Override
	public void startElement(String uri, String localName, String name,
			Attributes atts) throws SAXException {
		nodeName = localName;
		if (localName.equals("group")) {
			//读到group开始元素时创建GroupEntity对象
			groupEntity = new GroupEntity();
		} else if (localName.equals("member")){
			//读到member开始元素时创建MemberEntity对象
			memberEntity = new MemberEntity();
		} else if (localName.equals("groupID")) {
			startCDATA();
		} else if (localName.equals("groupName")) {
			startCDATA();
		} else if (localName.equals("name")) {
			startCDATA();
		} else if (localName.equals("age")) {
			startCDATA();
		} 

	}

	@Override
	public void endElement(String uri, String localName, String name)
			throws SAXException {
		nodeName = null;
		if (localName.equals("group")) {
			//读到group结束元素时添加GroupEntity对象添加到集合
			groupEntities.add(groupEntity);
		} else if (localName.equals("member")) {
			//读到member结束元素时将MemberEntity对象添加到集合
			groupEntity.getMemberEntities().add(memberEntity);
		} else if (localName.equals("groupID")) {
			endCDATA();
			groupEntity.setGroupId(getCDataString());
		} else if (localName.equals("groupName")) {
			endCDATA();
			groupEntity.setGroupName(getCDataString());
		} else if (localName.equals("name")) {
			endCDATA();
			memberEntity.setName(getCDataString());
		} else if (localName.equals("age")) {
			endCDATA();
			memberEntity.setAge(getCDataString());
		} 
	}

	private String getCDataString() {
		return cData.toString();
	}

	// 重新开始CDATA
	@Override
	public void startCDATA() throws SAXException {
		if (cData == null) {
			cData = new StringBuffer();
		} else {
			cData.delete(0, cData.length());
		}
		super.startCDATA();
	}

	@Override
	public void endCDATA() throws SAXException {

		super.endCDATA();
	}

	public ArrayList<GroupEntity> getResult() {
		return groupEntities;
	}

}
   通过 DataParseHandler的getResult()方法可以获取到解析xml数据成功后的实体集合。在创xml解析数据对应的DataParseHandler类后,还需要将该类的对象和需要解析的xml数据关联起来,于是就有了XmlParserUtil工具类。

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

package com.steven.android.sax.xml.util;

import java.io.StringReader;

import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
import org.xml.sax.ext.DefaultHandler2;
/**
 *  描述:Sax解析工具类
 * @author stevenhu223
 *
 */
public class XmlParserUtil {

	/**
	 * 关联DefaultHandler2和xml数据进行解析
	 * @param handler
	 * @param xml
	 */
	public static void parserXMLByHandler(DefaultHandler2 handler,String xml) {
		XMLReader xmlReader;
		InputSource input = getInputSouceByString(xml);
		try {
			SAXParserFactory s = SAXParserFactory.newInstance();
			xmlReader = s.newSAXParser().getXMLReader();
			xmlReader.setContentHandler(handler);
			xmlReader.parse(input);

		} catch (Exception e) {

			e.printStackTrace();
		}
	}
	
	/**
	 * 通过字符串获取流
	 * @param xmlStr
	 * @return
	 */
	public static InputSource getInputSouceByString(String xmlStr) {
		StringReader sr = new StringReader(xmlStr);
		InputSource is = new InputSource(sr);
		return is;

	}
	
}

  所以,通过创建对应的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中的xml、json格式数据解析_第3张图片

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

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

{
  "dataContent": {
    "group": [
      {
        "groupID": "1",
        "groupName": "第一组",
        "member": [
          {
            "name": "张三",
            "age": "22"
          },
          {
            "name": "李四",
            "age": "24"
          },
          {
            "name": "欧阳雪",
            "age": "18"
          }
        ]
      },
      {
        "groupID": "2",
        "groupName": "第二组",
        "member": [
          {
            "name": "司徒静",
            "age": "19"
          },
          {
            "name": "叶笙",
            "age": "26"
          },
          {
            "name": "杨风",
            "age": "25"
          }
        ]
      },
      {
        "groupID": "3",
        "groupName": "第三组",
        "member": [
          {
            "name": "王龙",
            "age": "32"
          },
          {
            "name": "西门胜男",
            "age": "21"
          },
          {
            "name": "张铬",
            "age": "45"
          }
        ]
      }
    ]
  }
}

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

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

package com.steven.android.jackson.activity;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.type.TypeReference;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.widget.ExpandableListView;
import com.steven.android.jackson.adapter.ExpandAdapter;
import com.steven.android.jackson.entity.JsonResponseEntity;
/**
 * 描述:主页面
 * @author stevenhu223
 *
 */
public class MainActivity extends Activity {
	
	private ExpandableListView mExpandableListView;
	private ExpandAdapter mAdapter;
	private ObjectMapper mObjectMapper;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		mExpandableListView = (ExpandableListView) findViewById(R.id.expanlist_content);
		mObjectMapper = new ObjectMapper();
		try {
			parseJsonData();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

	/**
	 * json数据格式解析
	 * @throws Exception
	 */
	private void parseJsonData()  throws Exception{
		InputStream inputStream = getResources().getAssets().open("jsonData");
		String dataContent = convertStreamToString(inputStream);
		try {
			JsonResponseEntity datEntity = mObjectMapper.readValue(dataContent,
					new TypeReference<JsonResponseEntity>() {
					});
			mAdapter = new ExpandAdapter(this, datEntity.getDataContent().getGroup());
			mExpandableListView.setAdapter(mAdapter);
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
	}
	
	/**
	 * 输入流转字符串
	 * @param is
	 * @return
	 */
	public String convertStreamToString(InputStream is) {

		BufferedReader reader = new BufferedReader(new InputStreamReader(is));
		StringBuilder sb = new StringBuilder();
		String line = null;
		try {
			while ((line = reader.readLine()) != null) {
				sb.append(line);
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				is.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return sb.toString();

	}
	
}
  代码中,parseJsonData方法实现jackson解析json格式数据,ObjectMapper来自jackson包,通过调用mObjectMapper对象readValue函数就可以实现对json数据的解析。我们来看看JsonResponseEntity实体类的代码。

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

package com.steven.android.jackson.entity;

public class JsonResponseEntity {

	/**
	 * jackson解析有严格的规定,变量名要和对应的元素名一致,否则解析会时会报错
	 */
	private DataContentEntity dataContent;

	public DataContentEntity getDataContent() {
		return dataContent;
	}

	public void setDataContent(DataContentEntity dataContent) {
		this.dataContent = dataContent;
	}
	
}
  值得注意的是,jackson解析有严格的实体类变量名对应json数据中的key名相同的限制,如果不一致,解析将会有问题。变量名dataContent对应的就是jsonData文件内容中的第一个key(dataContent);接下来来列出的其他实体类中的变量名,集合名都要和jsonData文件内容中的一致。
  4.DataContentEntity.java文件代码如下:

package com.steven.android.jackson.entity;

import java.util.List;

public class DataContentEntity {

	//变量名对应json内容中的group
	private List<GroupEntity> group;

	public List<GroupEntity> getGroup() {
		return group;
	}

	public void setGroup(List<GroupEntity> group) {
		this.group = group;
	}
}
  5.GroupEntity文件代码如下:

package com.steven.android.jackson.entity;

import java.util.ArrayList;
import java.util.List;

public class GroupEntity {
	
	private String groupID; //变量名对应json内容中的groupID
	private String groupName; //变量名对应json内容中的groupName
	//变量名对应json内容中的member
	private List<MemberEntity> member = new ArrayList<MemberEntity>();

	public String getGroupID() {
		return groupID;
	}

	public void setGroupID(String groupID) {
		this.groupID = groupID;
	}

	public String getGroupName() {
		return groupName;
	}

	public void setGroupName(String groupName) {
		this.groupName = groupName;
	}

	public List<MemberEntity> getMember() {
		return member;
	}

	public void setMember(List<MemberEntity> member) {
		this.member = member;
	}

}
  6.MemberEntity.java文件代码如下:
package com.steven.android.jackson.entity;

public class MemberEntity {

	private String name; //变量名对应json内容中的name
	private String age; //变量名对应json内容中的age

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getAge() {
		return age;
	}

	public void setAge(String age) {
		this.age = age;
	}

}
  以上为jackson解析相关的实体类。通过MainActivity的parseJson方法就可以将json数据解析成封装的DataJsonResponseEntity了。

 四。jackson数据转换解析

     jackson包不仅仅是单纯的解析json格式数据,还可以双向解析,甚至可以将json数据解析成map映射等。接下来将主要介绍Jackson包的json与bean(实体类)、Map与json之间的双向解析。

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

Android中的xml、json格式数据解析_第4张图片

  工程中,assets目录中的jsonData文件内容为一些相关销售报表数据。

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

{
    "retCode": "0",
    "retMsg": "success",
    "chart": {
        "caption": "2014季度销售报表汇总",
        "subcaption": "2014季度",
        "xaxisname": "销售月份",
        "yaxisname": "销售额度",
        "numberprefix": "$"
    },
    "data": [
        {
            "label": "一月",
            "value": "17400"
        },
        {
            "label": "二月",
            "value": "19800"
        },
        {
            "label": "三月",
            "value": "21800"
        },
        {
            "label": "四月",
            "value": "23800"
        },
        {
            "label": "五月",
            "value": "29600"
        },
        {
            "label": "六月",
            "value": "27600"
        },
        {
            "label": "七月",
            "value": "31800"
        },
        {
            "label": "八月",
            "value": "39700"
        },
        {
            "label": "九月",
            "value": "37800"
        },
        {
            "label": "十月",
            "value": "21900"
        },
        {
            "label": "十一月",
            "value": "32900"
        },
        {
            "label": "十二月",
            "value": "39800"
        }
    ]
}
    2.MainActivity.java文件代码如下:

package com.stevenhu.android.jacksontest;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.type.TypeReference;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
import com.stevenhu.android.jacksontest.bean.ChartsDataEntity;
import com.stevenhu.android.jacksontest.bean.ChartsEntity;
import com.stevenhu.android.jacksontest.bean.DataSetEntity;

public class MainActivity extends Activity{

	private String jsonData;
	private String mResult;
	private TextView text_content_show;
	private ChartsDataEntity mChartsDataEntity;
	private ObjectMapper mObjectMapper;
	private List<DataSetEntity> mDataSets;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		try {
			initialize();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		initBean();
		text_content_show.setText(parseMapToJson());
	}

	/**
	 * 初始化
	 */
	private void initialize() throws Exception{
		
		text_content_show = (TextView)findViewById(R.id.text_content_show);
		InputStream inputStream = getResources().getAssets().open("jsonData");
		jsonData = convertStreamToString(inputStream);
		
	}
	
	/**
	 * 输入流转字符串
	 * @param is
	 * @return
	 */
	public String convertStreamToString(InputStream is) {

		BufferedReader reader = new BufferedReader(new InputStreamReader(is));
		StringBuilder sb = new StringBuilder();
		String line = null;
		try {
			while ((line = reader.readLine()) != null) {
				sb.append(line);
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				is.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return sb.toString();

	}
	
	/**
	 * 初始化Bean
	 */
	private void initBean() {
		mObjectMapper = new ObjectMapper();
		mChartsDataEntity = new ChartsDataEntity();
		mDataSets = new ArrayList<DataSetEntity>();
		//ChartsEntity对象定义了图表属性
		ChartsEntity chart = new ChartsEntity();
		chart.setCaption("2014季度销售报表汇总");
		chart.setSubcaption("2014季度");
		chart.setXaxisname("销售月份");
		chart.setYaxisname("销售额度");
		chart.setNumberprefix("$");
				
		mChartsDataEntity.setChart(chart);
				
		initDataSet("一月", "17400");
		initDataSet("二月", "19800");
		initDataSet("三月", "21800");
		initDataSet("四月", "23800");
		initDataSet("五月", "29600");
		initDataSet("六月", "27600");
		initDataSet("七月", "31800");
		initDataSet("八月", "39700");
		initDataSet("九月", "37800");
		initDataSet("十月", "21900");
		initDataSet("十一月", "32900");
		initDataSet("十二月", "39800");
		initDataSet("一月", "17400");
				
	}
	
	/**
	 * 初始化DataSet
	 * @param month
	 * @param sale
	 */
	private void initDataSet(String month, String sale) {
		//DataSetEntity对象定义了图表的一组数据
		DataSetEntity dataSet = new DataSetEntity();
		dataSet.setLabel(month);
		dataSet.setValue(sale);
		mDataSets.add(dataSet);
		mChartsDataEntity.setData(mDataSets);
	}
	
	/**
	 * json数据格式转map
	 * @return
	 */
	private String parseJsonToMap() {
		String jsonString = "{\"name\":\"2014季度销售报表汇总\",\"chart\":{\"caption\":\"2014季度销售报表汇总\"," +
				" \"subcaption\":\"2014季度\",\"xaxisname\":\"销售月份\", \"yaxisname\":\"销售额度\", \"numberprefix\":\"$\"}}";
		if (null != mResult) {
			mResult = "";
		}
		
		try {
			Map<String , Map<String , Object>> maps = mObjectMapper.readValue(jsonString, Map.class);
			Set<String> keys = maps.keySet();
		    Iterator<String> iterator = keys.iterator();
		    while (iterator.hasNext()) {
		    	String key = iterator.next();
		    	mResult += key + ":" + maps.get(key) + "\n";
			}
		    
		    return mResult;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	
	/**
	 * map转json格式数据
	 * @return
	 */
	private String parseMapToJson() {
		Map<String , Object> map = new HashMap<String , Object>();
		String chartTitle = mChartsDataEntity.getChart().getCaption();
		map.put("name", chartTitle);
		map.put("chart", mChartsDataEntity.getChart());
		try {
			StringWriter sw = new StringWriter();
			JsonGenerator jsonGenerator = mObjectMapper.getJsonFactory().createJsonGenerator(sw);
			jsonGenerator.writeObject(map);
			jsonGenerator.close();
			String json = sw.toString();
			return json;
		} catch (Exception e) {
			// TODO: handle exception
		}
		return null;
	}
	
	/**
	 * json数据格式转实体类
	 * @return
	 */
	private String parseJsonToBean() {
	
		try {
			ChartsDataEntity chartsData = mObjectMapper.readValue(jsonData,
					new TypeReference<ChartsDataEntity>() {
					});
			ChartsEntity charts = chartsData.getChart();
			//String name = chartsData.getName();
			mResult = "RetCode-->" + chartsData.getRetCode() + "\n" + 
					"RetMsg-->" + chartsData.getRetMsg() + "\n" + 
			         "caption-->" + charts.getCaption() + "\n" + 
					"subcaption-->" + charts.getSubcaption() + "\n" + 
					"xaxisname-->" + charts.getXaxisname() + "\n" +
					"yaxisname-->" + charts.getYaxisname() + "\n" + 
					"numberprefix-->" + charts.getNumberprefix();
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
		
		List<DataSetEntity> datas = mChartsDataEntity.getData();
		
		for (DataSetEntity dataSet : datas) {
			mResult += "\n" + "label-->" + dataSet.getLabel()  + "  " + 
					"value-->" + dataSet.getValue();
		}
		
		return mResult;
	}
	
	/**
	 * 实体类转json格式数据
	 * @return
	 */
	private String parseBeanToJson() {
		
		try {
			StringWriter sw = new StringWriter();
			JsonGenerator jsonGenerator = mObjectMapper.getJsonFactory().createJsonGenerator(sw);
			//objectMapper.writeValue(jsonGenerator, mChartsDataEntity);
			jsonGenerator.writeObject(mChartsDataEntity);
			jsonGenerator.close();
			String json = sw.toString();
			return json;			
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
		return null;
	}
	
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}
	
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case R.id.item_map_to_json:
			text_content_show.setText(parseMapToJson());
			break;

		case R.id.item_json_to_map:
			text_content_show.setText(parseJsonToMap());
			break;
			
		case R.id.item_bean_to_json:
			text_content_show.setText(parseBeanToJson());
			break;
			
		case R.id.item_json_to_bean:
			text_content_show.setText(parseJsonToBean());
			break;
		}
		return true;
	}

}
  在MainActvity中,通过parseMapToJson、parseJsonToMap、parseBeanToJson、parseJsonToBean等方法实现json与bean、map与json之间的解析转换。其他相关的解析实体类的代码就不贴出来了,原理都是一样的。

你可能感兴趣的:(Android中的xml、json格式数据解析)