解析XML数据和JSON数据
首先要知道的一个问题 —— 数据到底是以什么样的格式在网络上传输的呢?随便传递一段文本肯定不行,因为另一方根本不知道这段文本的用途是什么。因此,我们会在网络上传输一些格式化后的数据,这种数据有一定的结构规格和语义,另一方收到数据消息之后就可以按照相同的结构规格进行解析,进而取出它想要的那部分内容。
网络上常用的传输数据的格式有两种 —— XML和JSON。
一、解析XML格式数据
1.1 Pull解析方法
上一节课学到发送Http请求并接收到来自服务器的数据,接收到的是一段String,这里赋值给变量response。接下来,我们要做的就是对response进行解析:
1. 首先要获取到一个XmlPullParserFactory的实例,并借助这个实例得到XmlPullParser对象,然后调用XmlPullParser的setInput()方法将服务器返回的XML数据设置进去就可以开始解析了;
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
XmlPullParser xmlPullParser = factory.newPullParser();
xmlPullParser.setInput(new StringReader(xmlData));
2. 解析过程通过getEventType()可以得到当前的解析时间,然后在一个while循环中逐个解析;
<span style="white-space:pre"> </span> int eventType = xmlPullParser.getEventType();
String id = "";
String name = "";
String version = "";
while (eventType != XmlPullParser.END_DOCUMENT) { //eventType!=END_DOCUMENT说明解析工作还没完成
String nodeName = xmlPullParser.getName();
switch (eventType) {
//开始解析某个节点
case XmlPullParser.START_TAG:
if ("id".equals(nodeName)) {
id = xmlPullParser.nextText();
} else if ("name".equals(nodeName)) {
name = xmlPullParser.nextText();
} else if ("version".equals(nodeName)) {
version = xmlPullParser.nextText();
}
break;
//完成解析某个结点
case XmlPullParser.END_TAG:
if ("app".equals(nodeName)) {
Log.d("MainActivity", "id is" + id);
Log.d("MainActivity", "name is" + name);
Log.d("MainActivity", "version is" + version);
}
break;
default:
break;
}
eventType = xmlPullParser.next(); //调用next()方法获取下一个解析事件
}
解析前的xml数据和解析后的数据如下(左图是网络上打开的xml文件,右图是解析后在LogCat中的打印日志):
1.2 SAX解析方法
1. 要使用SAX方法,我们要新建一个继承自DefaultHandler,并重写父类的五个方法,如下:public class SAXParseHandler extends DefaultHandler {
private String nodeName;
//分别定义了StringBuilder对象
private StringBuilder id;
private StringBuilder name;
private StringBuilder version;
//开始解析xml的时候调用
@Override
public void startDocument() throws SAXException {
super.startDocument();
//初始化各个StringBuilder
id = new StringBuilder();
name = new StringBuilder();
version = new StringBuilder();
}
@Override
public void endDocument() throws SAXException {
super.endDocument();
}
//开始解析某个结点(元素)时调用
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
super.startElement(uri, localName, qName, attributes);
//记录当前结点名
nodeName = localName;
}
//结束解析某个结点时调用
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
super.endElement(uri, localName, qName);
//判断如果app结点已经解析完成,就在日志中打印出来
if ("app".equals(localName)){
Log.d("ContentHandler","id is"+id.toString().trim()); //因为id中可能含有回车或换行符的,用trim()移除字符串两侧的空白字符
Log.d("ContentHandler","name is"+name.toString().trim());
Log.d("ContentHandler","version is"+version.toString().trim());
//最后要将StringBuilder清空,不然会影响下一次的内容读取
id.setLength(0);
name.setLength(0);
version.setLength(0);
}
}
//获取结点中内容的时候调用
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
super.characters(ch, start, length);
//根据当前的结点名判断将内容添加到哪一个StringBuilder对象中
if ("id".equals(nodeName)){
id.append(ch,start,length);
}else if ("name".equals(nodeName)){
name.append(ch, start, length);
}else if ("version".equals(nodeName)){
version.append(ch, start, length);
}
}
}
2. 创建ContentHelper后,在MAinActivity中的封装并调用一个 parseXMLWithSAX(String xmlData) 方法,用来解析数据:
SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
SAXParser saxParser = saxParserFactory.newSAXParser();
XMLReader xmlReader = saxParser.getXMLReader();
SAXParseHandler saxParseHandler = new SAXParseHandler();
xmlReader.setContentHandler(saxParseHandler); //将saxParseHandler十二只到XMLReader中
try {
xmlReader.parse(new InputSource(new StringReader(xmlData)));
} catch (IOException e) {
e.printStackTrace();
}
运行后,在LogCat中的日志的结果和上面用Pull是一样的。
二、解析JSON格式数据
比起XML,JSON的主要优势在于它的体积更小,在网络上传输的时候可以更省流量。但缺点在于,它的语义性差,看起来不如XML直观。2.1 使用JSONObject
这里创建一个parseJSONWithJSONObject(String jsonData) 方法,来解析JSON数据:
private void parseJSONWithJSONObject(String jsonData){
try {
JSONArray jsonArray = new JSONArray(jsonData);
for (int i = 0; i <jsonArray.length() ; i++) {
JSONObject jsonObject = jsonArray.getJSONObject(i);
String id = jsonObject.getString("id");
String name = jsonObject.getString("name");
String version = jsonObject.getString("version");
Log.d("MainActivity","id is"+id);
Log.d("MainActivity","name is"+name);
Log.d("MainActivity","version is"+version);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
首先我们要看jsonData是一个什么样的数据(见下图),由于我们要获得的网络数据是一个JSON数据,因此这里首先是将服务器返回的数据传入到了一个JSONArray对象中。然后遍历数组,从中取出的每一个元素都是一个JSONObject对象,每个JSONObject对象又包含id、name、version这些数据,再调用getString方法将这些数据取出即可。
2.2 使用GSON
GSON是谷歌提供的一个开源库,让JSON的解析变得前所未有的简单。首先,我们要在项目中添加一个GSON的Jar包,通过AS设置中的plugins搜索添加即可。
GSON的神奇在于它可以将一段JSON格式的数据自动映射成一个对象,从而不需要手动去编写代码解析了。比如一段JSON格式的数据如下:
{"name":"Tom","age":20}
我们只需要定义一个Person类,并加入name和age这两个字段,然后调用如下代码即可将JSON数据自动解析成一个Person对象:
Gson gson = new Gson();
Person person = gson.fromJson(jsonData,Person.class);
TIP:对于有些比较复杂的JSON数据,我们可能需要定义很多类来解析,这里提供一个插件——GsonFormat,可以将JSON自动转成Java类(好东西,能够省不少时间呐!)
拾遗:
1.
http://www.jsons.cn —— 一个神奇的网站,可以进行JSON的校验、格式化、生成实体类(和上文中GsonFormat功能相似,个人感觉这个更好用)等功能,能够大大提供工作效率;