市面上有许多API提供商,JSON和XML成为了主要的信息载体,数据解析是相当重要。
1.JSON,由字符串根据特定的格式形成的,传输和解析的速度都非常快。
2.XML,标签式文档,易于拓展,性能没JSON好,但处理大量的数据或者复杂的数据比JSON好使。
本帖用实例代码详解四种数据解析方式,两种是XML的,两种是JSON的。至于JSON和XML的写法规则,大家都懂的,没必要写了。
JSON:Android自带的JSON解析,Gson谷歌的东西。
XML:SAXPaser,XmlPullPaser,这两种性能较好,适合移动设备。
先看看数据结构和需求,需求是,找出这个school里B班的所有学生的信息。
school
classA
学生信息,id=101,classmate=Ben
.............................................................
.............................................................
classB
.............................................................
.............................................................
. ............................................................
classC
.............................................................
.............................................................
.............................................................
一、先来JSON,看看数据如下图:
{
"school":{
"classA":[
{
"id":"101",
"classmate":"Ben"
},
{
"id":"102",
"classmate":"Bell"
},
{
"id":"103",
"classmate":"Bean"
}
],
"classB":[
{
"id":"201",
"classmate":"Peter"
},
{
"id":"202",
"classmate":"Paul"
},
{
"id":"203",
"classmate":"Po"
}
],
"classC":[
{
"id":"301",
"text":"Sarah"
},
{
"id":"302",
"text":"Steven"
},
{
"id":"303",
"text":"Sam"
}
]
}
}
(1)Gson
Gson有个好处,可以根据JavaBean的结构。
先根据上述数据写个结构先,GsonBean.java。
规则是JSONOject的话用类对象(除了String这个类,还可以自定义或其他的),JSONArray的话用List集合(集合里的类除了String也可以放自定义或其他的)。
第一层,school的内容是个JSONOject,用一个自定义School类定义。
第二层,school的内容这个JSONOject里面放的是三个班的信息,自定义School类放的是定义三个班的信息。
第三层,三个class放的的内容都是一个JSONArray,用List集合。
第四层,上一层的List集合里,每个同学的信息是一个JSONOject,我没把同学的信息的JavaBean写在GsonBean.java,按照上述的规律,写在另外的JavaBean文件ClassmateBean.java。
GsonBean.java
package ljy.com.jsonandxmldemo;
import java.util.List;
/**
* Created by Administrator on 2016/4/21.
*/
public class GsonBean {
private School school;
public School getSchool() {
return school;
}
public void setSchool(School school) {
this.school = school;
}
public class School {
private List<ClassmateBeen> classA;
private List<ClassmateBeen> classB;
private List<ClassmateBeen> classC;
public List<ClassmateBeen> getClassA() {
return classA;
}
public void setClassA(List<ClassmateBeen> classA) {
this.classA = classA;
}
public List<ClassmateBeen> getClassB() {
return classB;
}
public void setClassB(List<ClassmateBeen> classB) {
this.classB = classB;
}
public List<ClassmateBeen> getClassC() {
return classC;
}
public void setClassC(List<ClassmateBeen> classC) {
this.classC = classC;
}
}
}
ClassmateBean.java
package ljy.com.jsonandxmldemo;
public class ClassmateBeen {
private String id;
private String classmate;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getClassmate() {
return classmate;
}
public void setClassmate(String classmate) {
this.classmate = classmate;
}
@Override
public String toString() {
return "id="+id+",classmate="+classmate;
}
}
以上两个JavaBean是JSON解析的模型。下面是解析的主要代码,GsonRunnable.java里的代码片段。
第一步,new一个Gson对象。
第二步,new一个TypeToken<T>(){}的对象,T是泛类,传入的是解析结构模型,就是刚刚定义的GsonBean。
第三步,gson.from(参数1,参数2)方法就是解析json的。
参数1是一个Reader类型或字符串。我的json数据是InputStream流的形式,这里传入的是new一个BufferReader传进去,当然也可以传入String。
参数2是上一步的type(解析结构模型)。
最终这个方法返回一个GsonBean的类型,已经在根据我设定的解析结构模型解析完了,可以获取数据了。
第四步,返回一个GsonBean对象,看上述JavaBean结构,先获取school,然后才到classB,最后得到一个List<ClassmateBean>集合,遍历这个集合获取B班所有同学的信息。
StringBuffer sb=new StringBuffer();
Gson gson=new Gson();
Type type=new TypeToken<GsonBean>(){}.getType();
GsonBean bean=gson.fromJson(new BufferedReader(new InputStreamReader(is)),type);
List<ClassmateBeen> classB_list=bean.getSchool().getClassB();
(2)Android自带的JSON解析
Android自带的JSONOject和JSONArray,使用起来也是非常方便的。比起Gson的json解析就少了个数据模块化的过程而已。
同样的数据和需求,下面来分析下代码:
JsonRunnable.java 【流转为String】的方法。
传入的数据是流的形式,首先要有一个把流转为String的方法。这个没啥好说的,拷贝就行了。
private String Is2String(InputStream is) {
StringBuffer buff=new StringBuffer();
BufferedReader re=new BufferedReader(new InputStreamReader(is));
String temp=null;
try {
while ((temp=re.readLine())!=null){
buff.append(temp);
temp=null;
}
return buff.toString();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
JsonRunnable.java 解析的片段第一步,因为数据最外层的是一个JSONObject,所以new一个JSONObject对象,new JSONObject(参数),参数是一个字符串。
第二步,可以根据节点get相应的东西,先get一下school的,school的内容是一个JSONObject,所以使用方法getJSONObject("school"),参数是一个节点的名称。
第三步,classB的内容是一个JSONArray,所以使用方法getJSONArray("classB")。
第四步,最终遍历得到的这个classB的内容的JSONArray,就可以获取B班同学的信息。
</pre><pre name="code" class="java"> String json=Is2String(is);
if(json!=null){
try {
JSONArray arr=new JSONObject(json).getJSONObject("school").getJSONArray("classB");
JSONObject temp;
for(int i=0;i<arr.length();i++){
temp=arr.getJSONObject(i);
sb.append("id="+temp.getString("id")
+",classmate="+temp.getString("classmate")
+"\r\n");
}
} catch (JSONException e) {
e.printStackTrace();
}
<span style="white-space:pre"> </span>}
二、再来XML,看看数据,我把用了上面JSON的数据,写成XML。
也可以通过[在线互换格式的数据的网站]转过来。
数据如下图:
<?xml version="1.0" encoding="utf-8"?>
<school>
<classA>
<classmate id="101">Ben</classmate>
<classmate id="102">Bell</classmate>
<classmate id="103">Bean</classmate>
</classA>
<classB>
<classmate id="201">Peter</classmate>
<classmate id="202">Paul</classmate>
<classmate id="203">Po</classmate>
</classB>
<classC>
<classmate id="301">Sarah</classmate>
<classmate id="302">Steven</classmate>
<classmate id="303">Sam</classmate>
</classC>
</school>
(1)SAXPaser
package ljy.com.jsonandxmldemo;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Administrator on 2016/4/20.
*/
public class SaxHandler extends DefaultHandler {
private List<ClassmateBeen> classb_list = null;
private ClassmateBeen classb = null;
private boolean isClassB = false;
private boolean isClassB_ele = false;
public List<ClassmateBeen> getData() {
return classb_list;
}
public SaxHandler() {
classb_list = new ArrayList<>();
}
@Override
public void startDocument() throws SAXException {
super.startDocument();
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
super.startElement(uri, localName, qName, attributes);
// Log.d("SAX","uri="+uri.toString()+",localname="+localName
// +",attributes=["+attributes.getLocalName(0)+","+attributes.getQName(0)+","+attributes.getValue(0)+"]");
if (qName.equals("classB")) {
isClassB = true;
} else if (isClassB && qName.equals("classmate")) {
classb = new ClassmateBeen();
classb.setId(attributes.getValue(0));
isClassB_ele = true;
} else {
return;
}
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
if (!isClassB) return;
super.characters(ch, start, length);
if (isClassB_ele)
classb.setClassmate(new String(ch, start, length));
isClassB_ele = false;
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if (!isClassB) return;
super.endElement(uri, localName, qName);
if (qName.equals("classB")) {
isClassB = false;
return;
} else if (isClassB && qName.equals("classmate")) {
classb_list.add(classb);
classb = null;
}
}
@Override
public void endDocument() throws SAXException {
super.endDocument();
}
}
try {
SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser();
SaxHandler saxHandler = new SaxHandler();
saxParser.parse(is, saxHandler);
StringBuffer sb = new StringBuffer();
for (ClassmateBeen c : saxHandler.getData()) {
// Log.d("sax",c.getId()+","+c.getName());
sb.append(c.toString());
sb.append("\r\n");
}
sb.append("paser for SAXParser\r\n");
callback.CallbackData(sb);
// Log.d("sax","end");
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
(2)XmlPullPaser
private StringBuffer paserXML(InputStream is) {
StringBuffer sb = new StringBuffer();
List<ClassmateBeen> classB_Member = null;
ClassmateBeen classmate = null;
org.xmlpull.v1.XmlPullParser paser = null;
try {
paser = XmlPullParserFactory.newInstance().newPullParser();
paser.setInput(is, "utf-8");
int eventCode = paser.getEventType();
boolean isClassB = false;
while (eventCode != org.xmlpull.v1.XmlPullParser.END_DOCUMENT) {
switch (eventCode) {
case org.xmlpull.v1.XmlPullParser.START_DOCUMENT:
classB_Member = new ArrayList<>();
break;
case org.xmlpull.v1.XmlPullParser.START_TAG:
if (paser.getName().equals("classB")) {
isClassB = true;
} else if (isClassB && paser.getName().equals("classmate")) {
classmate = new ClassmateBeen();
classmate.setId(paser.getAttributeValue(0));
//现在位置到了<classmate>标签,跳到下一部分,也就是两个标签之间的内容
paser.next();
classmate.setClassmate(paser.getText());
} else {
break;
}
break;
case org.xmlpull.v1.XmlPullParser.END_TAG:
if (!isClassB) break;
if (paser.getName().equals("classB")) {
isClassB = false;
} else if (isClassB && paser.getName().equals("classmate")) {
classB_Member.add(classmate);
classmate = null;
}
break;
}
eventCode = paser.next();
}
for (ClassmateBeen c : classB_Member)
sb.append(c.toString()+ "\r\n");
sb.append("paser for XmlPullParser\r\n");
return sb;
} catch (XmlPullParserException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
while (eventCode != org.xmlpull.v1.XmlPullParser.END_DOCUMENT) {
.........................省略一串代码跟上面片段一致。
if(classB_Member!=null && classB_Member.size()==2 )
eventCode = org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
else
eventCode = paser.next();
}
demo简单的效果图: