前言
网络上传输数据最常用的格式有两种:XML和JSON。
相比于JSON,XML优点是数据语义性强,很容易看的懂,容易书写。同时缺点也很明显,体积比JSON大,传输速率不及JSON。
即使如此,XML仍然是一种很重要的数据格式,如:Android开发过程中所有的资源文件都是XML格式。
博主前段时间面试一家公司,其中一道线下编程题就是实现XML构造器,还不允许用现有的XML框架。ORZ 给跪了,折腾了好久,虽然最后勉强算是完成任务,但是还是觉得跟一些框架相比实现的效果太差。
本文主要讲解Pull和SAX两种解析方式。这两种解析方式的jar是内置在android sdk中的所以不用导入,但是在Java中使用则需要导入。
本文两种方式以下面一段数据为例:
<apps>
<app>
<id>1</id>
<name>google map</name>
<version>1.0</version>
</app>
<app>
<id>2</id>
<name>google Chrome</name>
<version>2.1</version>
</app>
<app>
<id>3</id>
<name>google play</name>
<version>2.3</version>
</app>
</apps>
Pull
直接上Pull方式的代码方法,注释已经写得很清楚了,直接看代码即可。
如果不懂的可以复制代码,运行一下,打印一些关键地方的变量的结果就行了。
/**
* @param xml XML数据的String形式
*/
private void pullXML(String xml) {
try {
//获取XmlPullParserFactory实例
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
//根据实例获取XmlPullParser对象
XmlPullParser xmlPullParser = factory.newPullParser();
//设置xml数据
xmlPullParser.setInput(new StringReader(xml));
//获取当前的解析事件
int eventType = xmlPullParser.getEventType();
int id = 0;
String name = null;
double version = 0;
//循环判断XmlPullParser.END_DOCUMENT解析工作是否完成
while (eventType != XmlPullParser.END_DOCUMENT) {
//获取当前节点的name
String node = xmlPullParser.getName();
switch (eventType) {
//对应节点解析开始XmlPullParser.START_TAG
case XmlPullParser.START_TAG:
if (node.equals("id")) {
id = Integer.parseInt(xmlPullParser.nextText());
} else if (node.equals("name")) {
name = xmlPullParser.nextText();
} else if (node.equals("version")) {
version = Double.parseDouble(xmlPullParser.nextText());
}
break;
//对应节点解析结束XmlPullParser.END_TAG
case XmlPullParser.END_TAG:
if (node.equals("app")) {
Log.i(TAG, "pullXML: " + id + "," + name + "," + version);
}
break;
}
//获取下一个解析事件
eventType = xmlPullParser.next();
}
} catch (Exception e) {
e.printStackTrace();
}
}
虽然整个过程不是很难,但是逻辑特别容易混乱,尤其是XML格式的数据比较复杂的时候。
SAX
相比于Pull方式,SAX更复杂,需要新建一个解析类,但是SAX更容易操作。
新建Myhandler类继承DefaultHandler
很明显整个解析的流程就是在以下五个方法中进行的,相比于Pull方式更加直接明了。
public class MyHandler extends DefaultHandler {
private static final String TAG = "MyHandler";
String node;
StringBuilder id;
StringBuilder name;
StringBuilder version;
/**
* 开始xml解析时调用,多用于初始化一些变量
*
* @throws SAXException
*/
@Override
public void startDocument() throws SAXException {
id = new StringBuilder();
name = new StringBuilder();
version = new StringBuilder();
}
/**
* 解析节点的时候调用,用于获取节点name
*
* @param uri
* @param localName
* @param qName
* @param attributes
* @throws SAXException
*/
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes)
throws SAXException {
node = localName;
}
/**
* 获取节点内容的时候调用,用于处理节点内容
*
* @param ch
* @param start
* @param length
* @throws SAXException
*/
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
if (node.equals("id")) {
id.append(ch, start, length);
} else if (node.equals("name")) {
name.append(ch, start, length);
} else if (node.equals("version")) {
version.append(ch, start, length);
}
}
/**
* 完成某个节点解析时调用
*
* @param uri
* @param localName
* @param qName
* @throws SAXException
*/
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if (localName.equals("app")) {
Log.i(TAG, "endElement: " + id.toString().trim() + "," + name.toString().trim() + ","
+ version.toString().trim());
//清空Stringbuilder内容,否则还会影响下次调用
id.setLength(0);
name.setLength(0);
version.setLength(0);
}
}
/**
* 完成整个xml解析后调用
*
* @throws SAXException
*/
@Override
public void endDocument() throws SAXException {
super.endDocument();
}
}
SAX过程
SAX方式的方法代码中注释依旧写得很清楚。
有什么地方不清晰的复制的代码运行一下,打印关键地方的结果就 很清楚了。
private void saxXML(String xmlData) {
try {
//获取实例化对象
SAXParserFactory factory = SAXParserFactory.newInstance();
//获取XMLReader对象
XMLReader reader = factory.newSAXParser().getXMLReader();
//获取刚才MyHandler对象H
MyHandler handler = new MyHandler();
//将handler设置到XMLReader中
reader.setContentHandler(handler);
//执行xml解析
reader.parse(new InputSource(new StringReader(xmlData)));
} catch (Exception e) {
e.printStackTrace();
}
}
总结
除Pull与SAX外还有DOM方式,由于用的不多此处不再详解。
Pull与SAX各有优缺,可以配合使用。
相信你看完本文,会觉XML格式数据解析相比于JSON还是很复杂的,尤其是在有GSON框架后,JSON的解析不要太简单。(JSON格式数据解析及GSON框架的使用详解)