Adroid开发之解析xml数据的两种方式

前言

在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 的内容清空掉,不然的话会影响下一次内容的读取。

修改MainActivity.java中的代码

/** * 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解析,这里后面再补上…

相关文章

引言 NOKIA 有句著名的广告语:“科技以人为本”。任何技术都是为了满足人的生产生活需要而产生的。具体...
Writer:BYSocket(泥沙砖瓦浆木匠) 微博:BYSocket 豆瓣:BYSocket Reprint it anywhere u want. 文章...
Writer:BYSocket(泥沙砖瓦浆木匠) 微博:BYSocket 豆瓣:BYSocket Reprint it anywhere u want. 文章...
http://blog.jobbole.com/79252/ 引言 NOKIA 有句著名的广告语:“科技以人为本”。任何技术都是为了满...
(点击上方公众号,可快速关注) 公众号:smart_android 作者:耿广龙|loonggg 点击“阅读原文”,可查看...
一、xml与xslt 相信所有人对xml都不陌生,其被广泛的应用于数据数据传输、保存与序列化中,是一种极为强...