全屏浏览
缩小浏览
回到页首

android基础---->XMl数据的解析

  在网络上传输数据时最常用的格式有两种,XML和JSON,下面首先学一下如何解析XML格式的数据,JSON的解析可以参见我的博客(android基础---->JSON数据的解析)。解析XML 格式的数据其实也有挺多种方式的,本节中我们学习比较常用的两种,Pull解析和SAX 解析。

 

目录导航

  1.  Pull解析的用法
  2.  Pull解析的代码
  3.  Sax解析的用法
  4.  Sax解析的代码
  5.  Sax与Pull的比较
  6.  友情链接

 

Pull解析的用法

 一、我们常用的五个事件:

  • START DOCUMENT:文档开始时,解析器还没有读取任何数据
  • START_TAG:解析到标签开头
  • TEXT:解析到元素的内容
  • END_TAG:解析在标签的末尾
  • END_DOCUMENT:文档结束,之后不会再解析了

二、PULL解析的步骤:

  • 创建一个XMLPULL工厂实例:

  XmlPullParserFactory factory = XmlPullParserFactory.newInstance();

  • 不指定命名空间的话,将使用默认的解析器。若要改变命名空间,用setNamespaceAware()这个方法:

  factory.setNamespaceAware(true);

  • 创建一个解析的实例:

  XmlPullParser xpp = factory.newPullParser();

  • 解析输入的数据:

  xpp.setInput ( new FileReader (filename ) );

  • 接下来就可以根据不同的事件,做不同的解析处理:一般用next()方法去得到下一个事件

 三、next()方法与nextToken()方法:

  • next()方法只能支持上述常用的5种事件:
  • nextToken()方法不但支持next()方法的事件,还额外支持:COMMENT, CDSECT, DOCDECL, ENTITY_REF, PROCESSING_INSTRUCTION, or IGNORABLE_WHITESPACE

 

Pull解析的代码

 

  • 我们在assets中创建了一个文件: linux.xml
<?xml version="1.0" encoding="utf-8"?>
<LOL>
    <person>
        <!-- 这里是盖伦的注释 -->
        <name sex="man">盖伦</name>
        <address>德玛西亚</address>
        <say>我将带头冲锋</say>
    </person>
    <person>
        <!-- 这里是亚索的注释 -->
        <name sex="man">亚索</name>
        <address>艾欧尼亚</address>
        <say>死亡如风,常伴吾身</say>
    </person>
    <person>
        <!-- 这里是瑞雯的注释 -->
        <name sex="girl">瑞雯</name>
        <address>诺克萨斯</address>
        <say>战争与谋杀之间,潜藏着我们的心魇</say>
    </person>
</LOL>
  •  在MainActivity.xml中定义一个方法,得到linux.xml文件的内容
// 得到xml的数据
private String getXMLData(String fileName) {
    StringBuffer stringBuffer = new StringBuffer();
    InputStream inputStream = null;
    BufferedReader bufferedReader = null;

    try {
        inputStream = getResources().getAssets().open(fileName);
        bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        String line = "";
        while ((line = bufferedReader.readLine()) != null) {
            stringBuffer.append(line + "\n");
        }
        bufferedReader.close();
        inputStream.close();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        try {
            if (bufferedReader != null) {
                bufferedReader.close();
            }
            if (inputStream != null) {
                inputStream.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    Log.i(TAG, stringBuffer.toString());
    return stringBuffer.toString();
}
  • 定义一个方法,用PULL解析得到的数据:
// pull解析xml数据
public void pullParse(View view) {
    String xmlData = getXMLData(fileName);
    try {
        XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
        XmlPullParser xmlPullParser = factory.newPullParser();
        xmlPullParser.setInput(new StringReader(xmlData));
        int eventType = xmlPullParser.getEventType();

        String name = "";
        String address = "";
        String say = "";
        String sex = "";

        while (eventType != XmlPullParser.END_DOCUMENT) {
            String nodeName = xmlPullParser.getName();
            switch (eventType) {
                case XmlPullParser.START_TAG: {
                    if ("name".equals(nodeName)) {
                        // sex与name的位置不能互换
              // sex = xmlPullParser.getAttributeValue(0);
                        sex = xmlPullParser.getAttributeValue(null, "sex");
                        name = xmlPullParser.nextText();
                    } else if ("address".equals(nodeName)) {
                        address = xmlPullParser.nextText();
                    } else if ("say".equals(nodeName)) {
                        say = xmlPullParser.nextText();
                    }
                    break;
                }
                // 完成解析某个结点
                case XmlPullParser.END_TAG: {
                    if ("person".equals(nodeName)) {
                        Log.d(TAG, "name: " + name);
                        Log.d(TAG, "address: " + address);
                        Log.d(TAG, "say: " + say);
                        Log.d(TAG, "sex: " + sex);
                    }
                    break;
                }
                default:
                    break;
            }
            eventType = xmlPullParser.next();
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}
  •  若要解析到<!-- -->里面的注释内容,需要做以下的修改:增加case,修改next()方法为nextToken()方法:
// 增加一个case,用于接收注释的事件
case XmlPullParser.COMMENT: {
        coment = xmlPullParser.getText();
        break;
    }
    default:
        break;
}
eventType = xmlPullParser.nextToken();  // 此处为修改部分
  • 打印日志如下:(增加了注释的功能)
03-16 18:09:59.662 24745-24745/com.example.linux.xmlparsetest D/MainActivity: name: 盖伦
03-16 18:09:59.662 24745-24745/com.example.linux.xmlparsetest D/MainActivity: address: 德玛西亚
03-16 18:09:59.662 24745-24745/com.example.linux.xmlparsetest D/MainActivity: say: 我将带头冲锋
03-16 18:09:59.662 24745-24745/com.example.linux.xmlparsetest D/MainActivity: sex: man
03-16 18:09:59.662 24745-24745/com.example.linux.xmlparsetest D/MainActivity: comment:  这里是盖伦的注释 
03-16 18:09:59.662 24745-24745/com.example.linux.xmlparsetest D/MainActivity: name: 亚索
03-16 18:09:59.662 24745-24745/com.example.linux.xmlparsetest D/MainActivity: address: 艾欧尼亚
03-16 18:09:59.662 24745-24745/com.example.linux.xmlparsetest D/MainActivity: say: 死亡如风,常伴吾身
03-16 18:09:59.662 24745-24745/com.example.linux.xmlparsetest D/MainActivity: sex: man
03-16 18:09:59.662 24745-24745/com.example.linux.xmlparsetest D/MainActivity: comment:  这里是亚索的注释 
03-16 18:09:59.662 24745-24745/com.example.linux.xmlparsetest D/MainActivity: name: 瑞雯
03-16 18:09:59.662 24745-24745/com.example.linux.xmlparsetest D/MainActivity: address: 诺克萨斯
03-16 18:09:59.662 24745-24745/com.example.linux.xmlparsetest D/MainActivity: say: 战争与谋杀之间,潜藏着我们的心魇
03-16 18:09:59.662 24745-24745/com.example.linux.xmlparsetest D/MainActivity: sex: girl
03-16 18:09:59.662 24745-24745/com.example.linux.xmlparsetest D/MainActivity: comment:  这里是瑞雯的注释 

 

Sax解析的用法

 一、 SAX解析的简要:

SAX:事件驱动型的XML解析方式。顺序读取XML文件,不需要一次全部装载整个文件。当遇到像文件开头,文档结束,或者标签开头与标签结束时,会触发一个事件,用户通过在其回调事件中写入处理代码来处理XML文件,适合对XML的顺序访问,且是只读的。由于移动设备的内存资源有限,SAX的顺序读取方式更适合移动开发。

二、 SAX解析XML步骤:

  • 创建XML解析处理器。
  • 创建SAX解析器。
  • 将XML解析处理器分配给解析器。
  • 对文档进行解析,将每个事件发送给处理器。

三、SAX解析的过程:

  • 解析开始之前,需要向XMLReader注册一个ContentHandler,也就是相当于一个事件监听器,
  • 在ContentHandler中定义了很多方法,比如startDocument(),它定制了当在解析过程中,遇到文档开始时应该处理的事情。
  • 当 XMLReader读到合适的内容,就会抛出相应的事件,并把这个事件的处理权代理给ContentHandler,调用其相应的方法进行响应。

 

Sax解析的代码

  • 定义一个类ContentHandler,处理不同的事件:
package com.example.linux.xmlparsetest;

import android.util.Log;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

/**
 * Created by Linux on 2016/3/16.
 */
public class ContentHandler extends DefaultHandler {
    private final static String TAG = "MainActivity";
    private String nodeName;
    private StringBuilder name;
    private StringBuilder address;
    private StringBuilder say;private StringBuilder sex;

    // 文档开始时执行
    @Override
    public void startDocument() throws SAXException {
        name = new StringBuilder();
        address = new StringBuilder();
        say = new StringBuilder();
        sex = new StringBuilder();
        coment = new StringBuilder();
    }

    // 元素开始时执行
    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        // 记录当前结点名
        nodeName = localName;
        if (nodeName.equals("name") && attributes != null) {
            sex.append(attributes.getValue("sex"));
        }
    }

    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        // 根据当前的结点名判断将内容添加到哪一个StringBuilder对象中
        if ("name".equals(nodeName)) {
            name.append(ch, start, length);
        } else if ("address".equals(nodeName)) {
            address.append(ch, start, length);
        } else if ("say".equals(nodeName)) {
            say.append(ch, start, length);
        }
    }

    // 元素结束时执行
    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        if ("person".equals(localName)) {
            Log.d(TAG, "name is " + name.toString().trim());
            Log.d(TAG, "adress is " + address.toString().trim());
            Log.d(TAG, "say is " + say.toString().trim());
            Log.d(TAG, "sex is " + sex.toString().trim());
            // 最后要将StringBuilder清空掉
            name.setLength(0);
            address.setLength(0);
            say.setLength(0);
            sex.setLength(0);
        }
    }

    // 文档结束时
    @Override
    public void endDocument() throws SAXException {
        super.endDocument();
    }
}
  •  在MainActivity中定义方法,来进行SAX解析
// sax解析数据
public void saxParse(View view) {
    String xmlData = getXMLData(fileName);
    try {
        SAXParserFactory factory = SAXParserFactory.newInstance();
        XMLReader xmlReader = factory.newSAXParser().getXMLReader();
        ContentHandler handler = new ContentHandler();
        // 将ContentHandler的实例设置到XMLReader中
        xmlReader.setContentHandler(handler);
        // 开始执行解析
        xmlReader.parse(new InputSource(new StringReader(xmlData)));
    } catch (Exception e) {
        e.printStackTrace();
    }
}
  •  打印日志如下:
03-16 18:10:55.732 24745-24745/com.example.linux.xmlparsetest D/MainActivity: name is 盖伦
03-16 18:10:55.732 24745-24745/com.example.linux.xmlparsetest D/MainActivity: adress is 德玛西亚
03-16 18:10:55.732 24745-24745/com.example.linux.xmlparsetest D/MainActivity: say is 我将带头冲锋
03-16 18:10:55.732 24745-24745/com.example.linux.xmlparsetest D/MainActivity: sex is man
03-16 18:10:55.732 24745-24745/com.example.linux.xmlparsetest D/MainActivity: name is 亚索
03-16 18:10:55.732 24745-24745/com.example.linux.xmlparsetest D/MainActivity: adress is 艾欧尼亚
03-16 18:10:55.732 24745-24745/com.example.linux.xmlparsetest D/MainActivity: say is 死亡如风,常伴吾身
03-16 18:10:55.732 24745-24745/com.example.linux.xmlparsetest D/MainActivity: sex is man
03-16 18:10:55.732 24745-24745/com.example.linux.xmlparsetest D/MainActivity: name is 瑞雯
03-16 18:10:55.732 24745-24745/com.example.linux.xmlparsetest D/MainActivity: adress is 诺克萨斯
03-16 18:10:55.732 24745-24745/com.example.linux.xmlparsetest D/MainActivity: say is 战争与谋杀之间,潜藏着我们的心魇
03-16 18:10:55.732 24745-24745/com.example.linux.xmlparsetest D/MainActivity: sex is girl

 

Sax与Pull的比较

区别:

  • SAX解析器的工作方式是自动将事件推入注册的事件处理器进行处理,因此你不能控制事件的处理主动结束
  • PULL解析器的工作方式为允许你的应用程序代码主动从解析器中获取事件,正因为是主动获取事件,因此可以在满足了需要的条件后不再获取事件,结束解析

 

相似性:

  Pull解析器也提供了类似SAX的事件,开始文档START_DOCUMENT和结束文档END_DOCUMENT,开始元素START_TAG和结束元素END_TAG,遇到元素内容TEXT等,但需要调用next() 方法提取它们(主动提取事件)。

 

使用:

  如果在一个XML文档中我们只需要前面一部分数据,但是使用SAX方式或DOM方式会对整个文档进行解析,尽管XML文档中后面的大部分数据我们其实都不需要解析,因此这样实际上就浪费了处理资源。使用PULL方式正合适。

 

友情链接

至于SAX解析能不能解析到注释的内容,不知道各位有没有结果?

 

posted @ 2016-03-16 17:50  huhx  阅读(2524)  评论(2编辑  收藏  举报