在上一篇文章
Android-HttpClient连接网络获取数据中,简单使用了HttpURLConnection来获取网络数据,然而并没有对获取的数据做任何操作,比如解析从网络得到的数据。这篇文章,就来练习一下使用XmlPullParser解析XML。
XmlPullParser在Android源码中是使用的最多的一种XML解析器,当然还有其他的解析方式,比如:
SAX解析器。对于这些解析器的优缺点,不妨参阅一下其他朋友的文章:【Android】实现XML解析的几种技术 , 这篇文章对几种解析XML方式分析的蛮清楚。
关于XmlPullParser解析器,
在Android的历史上,Android有该接口的两个实现:
-
KXmlParser 通过
XmlPullParserFactory.newPullParser().
-
ExpatPullParser 通过
Xml.newPullParser().
但是大概在Android4.0的时候,Android改变了这种情况,Android让通过
Xml.newPullParser()获得实例也返回KXmlParser,同时也删除了ExpatPullParser类。对于这点,不妨看看现在关于这两种方式在源码中的实现方式:
/**
* Returns a new pull parser with namespace support.
*/
public static XmlPullParser newPullParser() {
try {
KXmlParser parser = new KXmlParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_DOCDECL, true);
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
return parser;
} catch (XmlPullParserException e) {
throw new AssertionError();
}
}
Xml.newPullParser()方式其实内部是new了一个KXmlParser对象并返回,所以 Xml.newPullParser()方式得到的是KXmlParser。而对于XmlPullParserFactory.newPullParser(),就Android 5.1来讲,是通过XmlPullParserFactory.newInstance()来得到KXmlParser,源码实现如下:
/**
* Creates a new instance of a PullParserFactory that can be used
* to create XML pull parsers. The factory will always return instances
* of {@link KXmlParser} and {@link KXmlSerializer}.
*/
public static XmlPullParserFactory newInstance () throws XmlPullParserException {
return new XmlPullParserFactory();
}
/**
* Protected constructor to be called by factory implementations.
*/
protected XmlPullParserFactory() {
parserClasses = new ArrayList<String>();
serializerClasses = new ArrayList<String>();
try {
parserClasses.add(Class.forName("org.kxml2.io.KXmlParser"));
serializerClasses.add(Class.forName("org.kxml2.io.KXmlSerializer"));
} catch (ClassNotFoundException e) {
throw new AssertionError();
}
}
从源码也可以看到不管是XmlPullParserFactory.newInstance(),还是XmlPullParserFactory.newPullParser(),最终返回的都是KXmlParser。
XmlPullParser是如何来解析XML中的内容呢?要真正理解XmlPullParser的工作原理,我觉的跟一下KXmlParser.java中被调用的方法,更能帮助自己理解解析的整个过程。
而我自己的理解是:XML中的各个元素节点都是配对的,XmlPullParser解析时先在XML开始元素设置一个TAG,然后开始逐个遍历,解析完一个XML元素节点,就通过next()方法跳到下一个,直到查询结束生成End事件。
下面以新浪天气API接口为例,获取北京当日的天气,并通过XmlPullParser解析返回的XML,代码虽然写的简单,有点繁琐,但是可以比较直观的看到如何解析XML中所需要的元素节点的内容。
返回的XML内容:
<?xml version="1.0" encoding="UTF-8"?>
<!-- published at 2015-11-12 14:02:03 -->
<Profiles>
<Weather>
<city>北京</city>
<status1>霾</status1>
<status2>小雨</status2>
<figure1>mai</figure1>
<figure2>xiaoyu</figure2>
<direction1>无持续风向</direction1>
<direction2>无持续风向</direction2>
<power1>≤3</power1>
<power2>≤3</power2>
<temperature1>9</temperature1>
<temperature2>6</temperature2>
<ssd>0</ssd>
<tgd1>10</tgd1>
<tgd2>10</tgd2>
<zwx>1</zwx>
<ktk>7</ktk>
<pollution>3</pollution>
<xcz>5</xcz>
<zho></zho>
<diy></diy>
<fas></fas>
<chy>5</chy>
<zho_shuoming>暂无</zho_shuoming>
<diy_shuoming>暂无</diy_shuoming>
<fas_shuoming>暂无</fas_shuoming>
<chy_shuoming>风衣、大衣、夹大衣、外套、毛衣、毛套装、西服套装、薄棉外套</chy_shuoming>
<pollution_l>轻度</pollution_l>
<zwx_l>最弱</zwx_l>
<ssd_l>较凉</ssd_l>
<fas_l>暂无</fas_l>
<zho_l>暂无</zho_l>
<chy_l>毛衣类</chy_l>
<ktk_l>建议开启(制热)</ktk_l>
<xcz_l>不适宜</xcz_l>
<diy_l>暂无</diy_l>
<pollution_s>对空气污染物扩散无明显影响</pollution_s>
<zwx_s>紫外线最弱</zwx_s>
<ssd_s>老年、幼儿、体弱者外出需要带上薄围巾、薄手套。</ssd_s>
<ktk_s>建议开启空调</ktk_s>
<xcz_s>洗车后当日有降水、大风或沙尘天气,不适宜洗车</xcz_s>
<gm>2</gm>
<gm_l>易发期</gm_l>
<gm_s>天气很凉,季节转换的气候,慎重增加衣服;较易引起感冒;</gm_s>
<yd>5</yd>
<yd_l>不适宜</yd_l>
<yd_s>天气阴冷,不适宜户外运动;</yd_s>
<savedate_weather>2015-11-12</savedate_weather>
<savedate_life>2015-11-12</savedate_life>
<savedate_zhishu>2015-11-12</savedate_zhishu>
<udatetime>2015-11-12 08:10:00</udatetime>
</Weather>
</Profiles>
package com.conway.network;
import android.util.Log;
import android.util.Xml;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.io.InputStream;
public class ParseWeatherXml {
private static final String TAG = "ParseWeatherXml";
public void parseWeather(InputStream in) throws XmlPullParserException, IOException {
try {
XmlPullParser xmlPullParser = Xml.newPullParser();
//XmlPullParserFactory xxxpullparser = XmlPullParserFactory.newInstance();
xmlPullParser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
xmlPullParser.setInput(in, null);
xmlPullParser.nextTag();
getWeatherInfo(xmlPullParser);
} finally {
// in.close();
}
}
/**
* @author conway
* @description 解析Profiles。
* @throws IOException
* @throws XmlPullParserException
*/
private void getWeatherInfo(XmlPullParser xmlPullParser)
throws XmlPullParserException, IOException {
xmlPullParser.require(XmlPullParser.START_TAG, null, "Profiles");
while (xmlPullParser.next() != XmlPullParser.END_TAG) {
if (xmlPullParser.getEventType() != XmlPullParser.START_TAG) {
continue;
}
setWeatherInfo(xmlPullParser);
}
}
/**
* @author conway
* @throws IOException
* @throws XmlPullParserException
*/
private void setWeatherInfo