Android解析xml文件

Android 生成xml文件

android解析XML总结(SAX、Pull、Dom三种方式)

在android开发中,经常用到去解析xml文件,常见的解析xml的方式有一下三种:SAX、Pull、Dom解析方式。最近做了一个android版的CSDN阅读器,用到了其中的两种(sax,pull),今天对android解析xml的这三种方式进行一次总结。
今天解析的xml示例(channels.xml)如下:

<?xml version="1.0" encoding="utf-8"?>
<channel>
<item id="0" url="http://www.baidu.com">百度</item>
<item id="1" url="http://www.qq.com">腾讯</item>
<item id="2" url="http://www.sina.com.cn">新浪</item>
<item id="3" url="http://www.taobao.com">淘宝</item>
</channel>
一、使用sax方式解析

基础知识:

 这种方式解析是一种基于事件驱动的api,有两个部分,解析器和事件处理器,解析器就是XMLReader接口,负责读取XML文档,和向事件处理器发送事件(也是事件源),事件处理器ContentHandler接口,负责对发送的事件响应和进行XML文档处理。

 下面是ContentHandler接口的常用方法

 public abstract void characters (char[] ch, int start, int length)

  这个方法来接收字符块通知,解析器通过这个方法来报告字符数据块,解析器为了提高解析效率把读到的所有字符串放到一个字符数组(ch)中,作为参数传递给character的方法中,如果想获取本次事件中读取到的字符数据,需要使用start和length属性。

public abstract void startDocument () 接收文档开始的通知

 public abstract void endDocument () 接收文档结束的通知

public abstract void startElement (String uri, String localName, String qName, Attributes atts) 接收文档开始的标签

public abstract void endElement (String uri, String localName, String qName) 接收文档结束的标签

在一般使用中为了简化开发,在org.xml.sax.helpers提供了一个DefaultHandler类,它实现了ContentHandler的方法,我们只想继承DefaultHandler方法即可。

另外SAX解析器提供了一个工厂类:SAXParserFactory,SAX的解析类为SAXParser 可以调用它的parser方法进行解析。

看了些基础以后开始上代码吧(核心代码,下载代码在附件)

public class SAXPraserHelper extends DefaultHandler {

    final int ITEM = 0x0005;

    List<channel> list;
    channel chann;
    int currentState = 0;

    public List<channel> getList() {
        return list;
    }

    /*
     * 接口字符块通知
*/
    @Override
    public void characters(char[] ch, int start, int length)
            throws SAXException {
        // TODO Auto-generated method stub
// super.characters(ch, start, length);
        String theString = String.valueOf(ch, start, length);
        if (currentState != 0) {
            chann.setName(theString);
            currentState = 0;
        }
        return;
    }

    /*
     * 接收文档结束通知
*/
    @Override
    public void endDocument() throws SAXException {
        // TODO Auto-generated method stub
        super.endDocument();
    }

    /*
     * 接收标签结束通知
*/
    @Override
    public void endElement(String uri, String localName, String qName)
            throws SAXException {
        // TODO Auto-generated method stub
        if (localName.equals("item"))
            list.add(chann);
    }

    /*
     * 文档开始通知
*/
    @Override
    public void startDocument() throws SAXException {
        // TODO Auto-generated method stub
        list = new ArrayList<channel>();
    }

    /*
     * 标签开始通知
*/
    @Override
    public void startElement(String uri, String localName, String qName,
            Attributes attributes) throws SAXException {
        // TODO Auto-generated method stub
        chann = new channel();
        if (localName.equals("item")) {
            for (int i = 0; i < attributes.getLength(); i++) {
                if (attributes.getLocalName(i).equals("id")) {
                    chann.setId(attributes.getValue(i));
                } else if (attributes.getLocalName(i).equals("url")) {
                    chann.setUrl(attributes.getValue(i));
                }
            }
            currentState = ITEM;
            return;
        }
        currentState = 0;
        return;
    }
}
private List<channel> getChannelList() throws ParserConfigurationException, SAXException, IOException
    {
        //实例化一个SAXParserFactory对象
        SAXParserFactory factory=SAXParserFactory.newInstance();
        SAXParser parser;
        //实例化SAXParser对象,创建XMLReader对象,解析器
        parser=factory.newSAXParser();
        XMLReader xmlReader=parser.getXMLReader();
        //实例化handler,事件处理器
        SAXPraserHelper helperHandler=new SAXPraserHelper();
        //解析器注册事件
        xmlReader.setContentHandler(helperHandler);
        //读取文件流
        InputStream stream=getResources().openRawResource(R.raw.channels);
        InputSource is=new InputSource(stream);
        //解析文件
        xmlReader.parse(is);
        return helperHandler.getList();
    }

从第二部分代码,可以看出使用SAX解析XML的步骤:
1、实例化一个工厂SAXParserFactory
2、实例化SAXPraser对象,创建XMLReader 解析器
3、实例化handler,处理器
4、解析器注册一个事件
4、读取文件流
5、解析文件

二、使用pull方式解析

基础知识:

  在android系统中,很多资源文件中,很多都是xml格式,在android系统中解析这些xml的方式,是使用pul解析器进行解析的,它和sax解析一样(个人感觉要比sax简单点),也是采用事件驱动进行解析的,当pull解析器,开始解析之后,我们可以调用它的next()方法,来获取下一个解析事件(就是开始文档,结束文档,开始标签,结束标签),当处于某个元素时可以调用XmlPullParser的getAttributte()方法来获取属性的值,也可调用它的nextText()获取本节点的值。

其实以上描述,就是对整个解析步骤的一个描述,看看代码吧

private List<Map<String, String>> getData() {
        List<Map<String, String>> list = new ArrayList<Map<String, String>>();
        XmlResourceParser xrp = getResources().getXml(R.xml.channels);

        try {
            // 直到文档的结尾处
            while (xrp.getEventType() != XmlResourceParser.END_DOCUMENT) {
                // 如果遇到了开始标签
                if (xrp.getEventType() == XmlResourceParser.START_TAG) {
                    String tagName = xrp.getName();// 获取标签的名字
                    if (tagName.equals("item")) {
                        Map<String, String> map = new HashMap<String, String>();
                        String id = xrp.getAttributeValue(null, "id");// 通过属性名来获取属性值
                        map.put("id", id);
                        String url = xrp.getAttributeValue(1);// 通过属性索引来获取属性值
                        map.put("url", url);
                        map.put("name", xrp.nextText());
                        list.add(map);
                    }
                }
                xrp.next();// 获取解析下一个事件
            }
        } catch (XmlPullParserException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return list;
    }
三、使用Dom方式解析

基础知识:

 最后来看看Dom解析方式,这种方式解析自己之前也没有用过(在j2ee开发中比较常见,没有做过这方面的东西),在Dom解析的过程中,是先把dom全部文件读入到内存中,然后使用dom的api遍历所有数据,检索想要的数据,这种方式显然是一种比较消耗内存的方式,对于像手机这样的移动设备来讲,内存是非常有限的,所以对于比较大的XML文件,不推荐使用这种方式,但是Dom也有它的优点,它比较直观,在一些方面比SAX方式比较简单。在xml文档比较小的情况下也可以考虑使用dom方式。

Dom方式解析的核心代码如下:

public static List<channel> getChannelList(InputStream stream)
    {
        List<channel> list=new ArrayList<channel>();
        
        //得到 DocumentBuilderFactory 对象, 由该对象可以得到 DocumentBuilder 对象
        DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
        
        try {
            //得到DocumentBuilder对象
            DocumentBuilder builder=factory.newDocumentBuilder();
            //得到代表整个xml的Document对象
            Document document=builder.parse(stream);
            //得到 "根节点" 
            Element root=document.getDocumentElement();
            //获取根节点的所有items的节点
            NodeList items=root.getElementsByTagName("item");  
            //遍历所有节点
            for(int i=0;i<items.getLength();i++)
            {
                channel chann=new channel();
                Element item=(Element)items.item(i);
                chann.setId(item.getAttribute("id"));
                chann.setUrl(item.getAttribute("url"));
                chann.setName(item.getFirstChild().getNodeValue());
                list.add(chann);
            }
            
        } catch (ParserConfigurationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SAXException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
        return list;
    }
总结一下Dom解析的步骤(和sax类似)

1、调用 DocumentBuilderFactory.newInstance() 方法得到 DOM 解析器工厂类实例。
2、调用解析器工厂实例类的 newDocumentBuilder() 方法得到 DOM 解析器对象
3、调用 DOM 解析器对象的 parse() 方法解析 XML 文档得到代表整个文档的 Document 对象。

四、总结

除以上三种外还有很多解析xml的方法,比如DOM4J、JDOM等等。但其基本的解析方式包含两种,一种是事件驱动的(代表SAX),另一种方式是基于文档结构(代表DOM)。其他的只不过语法不一样而已。

附(本文示例运行截屏):



转自

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容