写在前面:
测试的时候我申请了一个查询快递的接口,其返回的xml数据示例如下:
<root>
<resultcode>200</resultcode>
<reason>查询成功!</reason>
<result>
<company>顺丰</company>
<com>sf</com>
<no>575677355677</no>
<status>0</status>
<list>
<item>
<datetime>2013-06-25 10:44:05</datetime>
<remark>已收件</remark>
<zone>台州市</zone>
</item>
<item>
<datetime>2013-06-25 11:05:21</datetime>
<remark>快件在 台州 ,准备送往下一站 台州集散中心</remark>
<zone>台州市</zone>
</item>
......
</list>
</result>
</root>
一、Pull解析方式
1.获取XmlPull解析工厂的实例,并通过它获取一个解析器
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
XmlPullParser xmlPullParser = factory.newPullParser();
2.给解析器设置需要解析的数据
xmlPullParser.setInput(new StringReader(xmlData));
setInput()方法接收的是一个Reader对象,Demo中的网络请求采用的是上一篇文章通过http协议实现的,返回数据为String类型,这里通过StringReader将其封装一下即可。
3.开始逐个标签进行解析
int eventType = xmlPullParser.getEventType();
String dateTime = "";
String remark = "";
//开始解析数据
while(eventType!=XmlPullParser.END_DOCUMENT){
String nodeName = xmlPullParser.getName();
//Log.d(TAG, "parseNodeName:"+nodeName);
switch (eventType){
//开始解析某个节点
case XmlPullParser.START_TAG:
if("datetime".equals(nodeName)){
dateTime = xmlPullParser.nextText();
} else if("remark".equals(nodeName)){
remark = xmlPullParser.nextText();
}
break;
//完成解析某个节点
case XmlPullParser.END_TAG:
if("item".equals(nodeName)){
stringBuilder.append("时间:"+dateTime+"\r\n"+"内容:"+remark+"\r\n");
}
break;
default:
break;
}
eventType = xmlPullParser.next();
}
其中,getEventType()方法可以得到当前的解析事件,然后在while循环中不断的进行逐个标签的解析。如果当前的解析事件不等于XmlPullParser.END_DOCUMENT,说明解析工作还没有完成,调用next()方法来获取下一个解析事件。在while循环中,我们通过getName()方法得到当前标签的名字,如果发现标签名是我们想要数据的标签名,就调用nextText()方法来获取标签体的内容。
二、SAX解析方式
1.新建一个类去继承DefaultHandler然后重写其中的5个方法
public class ContentHandler extends DefaultHandler {
@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);
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
super.characters(ch, start, length);
}
@Override
public void endDocument() throws SAXException {
super.endDocument();
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
super.endElement(uri, localName, qName);
}
}
2.根据需要读取的数据添加成员变量(其中contentResult用于存储读取结果)
private String nodeName;
private StringBuilder dateTime,remark,contentResult;
3.开始XML解析时初始化成员变量
//在开始XML解析的时候调用
@Override
public void startDocument() throws SAXException {
dateTime = new StringBuilder();
remark = new StringBuilder();
contentResult = new StringBuilder();
}
4.解析标签时记录标签名
//在开始解析某个标签时调用
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
nodeName = localName;
}
5.解析标签体时,根据标签名筛选出我们需要的数据并存入成员变量
//在解析标签体内容时调用
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
if("datetime".equals(nodeName)){
dateTime.append(ch, start, length);
} else if("remark".equals(nodeName)){
remark.append(ch, start, length);
}
}
PS:在获取标签体中的内容时,characters()方法可能会被调用多次,一些换行符也被当作内容解析出来,需要针对该情况在代码中做好控制。
6.在解析完某个标签时,存储读取结果并清空临时数据
//在完成解析某个标签时调用
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if("item".equals(localName)){
contentResult.append("时间:"+dateTime.toString().trim()+"\r\n"+"内容:"+remark.toString().trim()+"\r\n");
//清空dateTime和remark避免影响下一条数据的读取
dateTime.setLength(0);
remark.setLength(0);
}
}
完成ContentHandler的编写工作之后,就可以正式开始SAX解析了。
7.获取SAX解析工厂的实例,并通过它获取一个解析器
SAXParserFactory factory = SAXParserFactory.newInstance();
XMLReader xmlReader = factory.newSAXParser().getXMLReader();
8.创建一个我们之前自定义的ContentHandler实例,并将它设置给解析器
ContentHandler handler = new ContentHandler();
//将ContentHandler的实例设置到XMLReader中
xmlReader.setContentHandler(handler);
9.开始解析
xmlReader.parse(new InputSource(new StringReader(xmlData)));
同样的,xmlData为请求网络返回的String类型数据,将其封装为Reader类型之后传给解析器解析。
10.获取解析结果
handler.getResult().toString();
这里的getResult()方法是我自定义ContentHandler时,创建的一个用于获取解析结果的方法:
public StringBuilder getResult(){
return contentResult;
}