前言
在android开发中,从服务器拿到的xml数据存在两种解析方式:
- Pull解析方式
- SAX解析方式
接下来我们来一一说一下具体用法。
这里为了测试,我们首先在测试服务器上放上一个get_date.xml文件,以方便我们终端来请求解析。文件内容如下:
1.Pull解析方式
代码如下:
- @Override
- public void onClick(View v) {
- switch (v.getId()) {
- case R.id.send_req:
- sendRequestWithHttpClient();
- break;
-
- default:
- break;
- }
- }
-
- // The code that request is Success
- private static final int REQUEST_SUCCESS = 200;
-
- // Encoding format
- private static final String UTF_8 = "UTF-8";
-
- /** * HttpClient * * The HttpClient was supported by Apache * */
- private void sendRequestWithHttpClient() {
-
- new Thread(new Runnable() {
-
- @Override
- public void run() {
- // this is a GET request
- try {
- HttpClient httpClient = new DefaultHttpClient();
- HttpGet httpGet = new HttpGet("http://127.0.0.1/get_data.xml");
- HttpResponse httpResponse = httpClient.execute(httpGet);
-
- if (httpResponse.getStatusLine().getStatusCode() == REQUEST_SUCCESS) {
- HttpEntity entity = httpResponse.getEntity();
- String response = EntityUtils.toString(entity,UTF_8);
-
- // Parse xml data by Pull method
- parseXMLWithPull(response);
-
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }).start();
-
-
- }
-
- /** * parse XML data by Pull method * * @param xmlData */
- private void parseXMLWithPull(String xmlData) {
- try {
- XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
- XmlPullParser xmlPullParser = factory.newPullParser();
- xmlPullParser.setInput(new StringReader(xmlData));
-
- int eventType = xmlPullParser.getEventType();
-
- String id = "";
- String name = "";
- String version = "";
- while (eventType != XmlPullParser.END_DOCUMENT) {
- String nodeName = xmlPullParser.getName();
- switch (eventType) {
- // Begin to parse a tag
- 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;
-
- // When we parsed a tag,print the infos
- case XmlPullParser.END_TAG:
- if ("app".equals(nodeName)) {
- Log.d("Info","id is " + id);
- Log.d("Info","name is " + name);
- Log.d("Info","version is " + version);
- }
- break;
- default:
- break;
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
这里首先要获取到一个XmlPullParserFactory 的 实 例 , 并 借 助 这 个 实 例 得 到 XmlPullParser 对 象 , 然 后 调 用
XmlPullParser 的 setInput()方法将服务器返回的 XML 数据设置进去就可以开始解析了。解析的过程也是非常简单,通过 getEventType()可以得到当前的解析事件,然后在一个 while 循环中不断地进行解析,如果当前的解析事件不等于 XmlPullParser.END_DOCUMENT,说明解析工作还没完成,调用 next()方法后可以获取下一个解析事件。在 while 循环中,我们通过 getName()方法得到当前结点的名字,如果发现结点名等于id、name 或 version,就调用 nextText()方法来获取结点内具体的内容,每当解析完一个 app结点后就将获取到的内容打印出来。
打印结果:
2.SAX解析方式
除了Pull方式来解析外,我们还可以用SAX方式来解析,用法上比Pull方式稍微复杂一些,但是语义方面更加清晰。
通常情况下我们都会新建一个类继承自 DefaultHandler,并重写父类的五个方法,如下所示:
这里说明一下上面几个方法的用处:
- startDocument() : 开始 XML 解析的时候调用
- startElement() : 开始解析某个结点的时候调用
- characters() : 在获取结点中内容的时候调用
- endElement() : 在完成解析某个结点的时候调用
- endDocument() : 在完成整个 XML 解析的时候调用
其中,startElement()、characters()和 endElement()这三个方法是有参数的,从 XML 中解析出的数据就会以参数的形式传入到这些方法中。需要注意的是,在获取结点中的内容时,characters()方法可能会被调用多次,一些换行符也被当作内容解析出来,我们需要针对这种情况在代码中做好控制。
接下来,我们来看看具体应用代码:
- import org.xml.sax.Attributes;
- import org.xml.sax.SAXException;
- import org.xml.sax.helpers.DefaultHandler;
-
- import android.util.Log;
-
- /** * 解析xml * */
- public class ContentHandler extends DefaultHandler {
-
- private String nodeName;
-
- private StringBuilder id;
-
- private StringBuilder name;
-
- private StringBuilder version;
-
- @Override
- public void startDocument() throws SAXException {
- id = new StringBuilder();
- name = new StringBuilder();
- version = new StringBuilder();
- }
-
- @Override
- public void endDocument() throws SAXException {}
-
- @Override
- public void startElement(String uri,String localName,String qName,Attributes attributes) throws SAXException {
- // 记录当前节点名
- nodeName = localName;
- }
-
- @Override
- public void endElement(String uri,String qName)
- throws SAXException {
- if ("app".equals(localName)) {
- Log.d("ContentHandler","id is " + id.toString().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 {
- // 根据当前的节点名判断将内容添加到哪一个StringBuilder中
- if ("id".equals(nodeName)) {
- id.append(ch,start,length);
- } else if ("name".equals(nodeName)) {
- name.append(ch,length);
- } else if ("version".equals(nodeName)) {
- version.append(ch,length);
- }
- }
-
-
- }
我们在startDocument()中初始化相关StringBuilder对象,接下来每当开始解析某个结点的时候,startElement()方法就会得到调用,其中 localName 参数记录着当前结点的名字,这里我们把它记录下来。接着在解析结点中具体内容的时候就会调用 characters()方法,我们会根据当前的结点名进行判断,将解析出的内容添加到哪一个 StringBuilder 对象中。最后在 endElement()方法中进行判断,如果 app 结点已经解析完成,就打印出 id、name 和 version 的内容。需要注意的是,目前 id、name 和 version 中都可能是包括回车或换行符的,因此在打印之前我们还需要调用一下 trim()方法,并且打印完成后还要将 StringBuilder 的内容清空掉,不然的话会影响下一次内容的读取。
- /** * HttpClient * * The HttpClient was supported by Apache * */
- private void sendRequestWithHttpClient() {
-
- new Thread(new Runnable() {
-
- @Override
- public void run() {
- // this is a GET request
- try {
- HttpClient httpClient = new DefaultHttpClient();
- HttpGet httpGet = new HttpGet("http://127.0.0.1/get_data.xml");
- HttpResponse httpResponse = httpClient.execute(httpGet);
-
- if (httpResponse.getStatusLine().getStatusCode() == REQUEST_SUCCESS) {
- HttpEntity entity = httpResponse.getEntity();
- String response = EntityUtils.toString(entity,UTF_8);
-
- // Parse xml data by SAX method
- parseXMLWithSAX(response);
-
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }).start();
-
-
- }
-
- /** * pares XML data by SAX method * * @param xmlData */
- private void parseXMLWithSAX(String xmlData) {
- try {
- SAXParserFactory factory = SAXParserFactory.newInstance();
- XMLReader reader = factory.newSAXParser().getXMLReader();
- ContentHandler handler = new ContentHandler();
- // 将contentHandler实例设置到reader中
- reader.setContentHandler(handler);
- // 开始解析
- reader.parse(new InputSource(new StringReader(xmlData)));
- } catch (Exception e) {
- e.printStackTrace();
- }
-
- }
附
除了上述两种解析方式外,还有一种DOM解析,这里后面再补上…