`

android中的xml处理

阅读更多

 

(翻译自http://www.ibm.com/developerworks/opensource/library/x-android/

 

写代码迟早都得跟xml打交道,java有两种常见的xml处理方式:SAX和DOM,在android平台上都可以用。另外,StAX是一种新的xml处理方式,android还没有提供原生支持,但是提供了一个功能类似的库 - XML pull parser,三种方式的使用分别如下。

 

 

- 首先,我们要处理的xml长得像这样(rss feed):

<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" >
    <channel>
        <title> android_news </title>
        <description> android_news </description>
        <link> http://www.androidster.com/android_news.php </link>

        <item>
            <title> Samsung S8000 to Run Android, Play DivX, Take Over the World </title>
            <link> http://www.androidster.com/android_news/</link>
            <description>A yet-to-be announced phone called the S8000 is being reported ... </description>
            <pubDate> Thu, 16 Apr 2009 07:18:51 +0100 </pubDate>
        </item>
        
        <item>
            <title> Android Cupcake Update on the Horizon </title>
            <link> http://www.androidster.com/android_news/android-cupcake-update- on-the-horizon </link>
            <description> all been waiting for is about to finally make it out ... </description>
            <pubDate> Tue, 14 Apr 2009 04:13:21 +0100 </pubDate>
        </item>
    </channel>
</rss
 
    这是一个rss feed,我们要提取其中的item信息,我们可以先为item定义一个数据模型(pojo):
public class Message {
    private static SimpleDateFormat FORMATTER = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z");

    private String title;
    private URL link;
    private String description;
    private Date date;

    public void setLink(String link) {
        try {
            this.link = new URL(link);
        } catch (MalformedURLException e) {
            throw new RuntimeException(e);
        }
    }

    public void setDate(String date) {
        try {
            this.date = FORMATTER.parse(date.trim());
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }

    // 省略其他的getter, setter
}
 

 

- 因为我们要采用几种方式来解析xml,因此我们可以定义一个基本的解析接口:
public interface FeedParser {
    List<Message> parse();
}
 
所有的parser都需要通过一个url从网络获取feed数据,我们可以让url在parser对象构造的时候传入,
下面是我们定义的一个基本的解析类:
public abstract class BaseFeedParser implements FeedParser {
    // XML tags
    static final String PUB_DATE = "pubDate";
    static final String DESCRIPTION = "description";
    static final String LINK = "link";
    static final String TITLE = "title";
    static final String ITEM = "item";
    
    final URL feedUrl;

    protected BaseFeedParser(String feedUrl){
        try {
            this.feedUrl = new URL(feedUrl);
        } catch (MalformedURLException e) {
            throw new RuntimeException(e);
        }
    }

    protected InputStream getInputStream() {
        try {
            return feedUrl.openConnection().getInputStream();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
 
方式一:使用SAX
public class SaxFeedParser extends BaseFeedParser {
    protected SaxFeedParser(String feedUrl){
        super(feedUrl);
    }
    
    public List<Message> parse() {
        SAXParserFactory factory = SAXParserFactory.newInstance();
        try {
            SAXParser parser = factory.newSAXParser();
            RssHandler handler = new RssHandler();
            parser.parse(this.getInputStream(), handler);
            return handler.getMessages();
        } catch (Exception e) {
            throw new RuntimeException(e);
        } 
    }
}
 或者,用android提供的xml工具类更简单:
import android.util.Xml;
public class AndroidSaxFeedParser extends BaseFeedParser {

    public AndroidSaxFeedParser(String feedUrl) {
        super(feedUrl);
    }

    public List<Message> parse() {
        RssHandler handler = new RssHandler();
        try {
            Xml.parse(this.getInputStream(), Xml.Encoding.UTF_8, handler);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return handler.getMessages();
    }

}
 
SAX的处理的重点在于,我们需要定义一个handler来解析,这个handler可以继承自:
org.xml.sax.helpers.DefaultHandler

public class RssHandler extends DefaultHandler {
    private List<Message> messages;
    private Message currentMessage;
    private StringBuilder builder;
    
    public List<Message> getMessages(){
        return this.messages;
    }

    @Override
    public void characters(char[] ch, int start, int length)
            throws SAXException {
        super.characters(ch, start, length);
        builder.append(ch, start, length);
    }

    @Override
    public void endElement(String uri, String localName, String name)
            throws SAXException {
        super.endElement(uri, localName, name);
        if (this.currentMessage != null){
            if (localName.equalsIgnoreCase(TITLE)){
                currentMessage.setTitle(builder.toString());
            } else if (localName.equalsIgnoreCase(LINK)){
                currentMessage.setLink(builder.toString());
            } else if (localName.equalsIgnoreCase(DESCRIPTION)){
                currentMessage.setDescription(builder.toString());
            } else if (localName.equalsIgnoreCase(PUB_DATE)){
                currentMessage.setDate(builder.toString());
            } else if (localName.equalsIgnoreCase(ITEM)){
                messages.add(currentMessage);
            }
            builder.setLength(0);    
        }
    }

    @Override
    public void startDocument() throws SAXException {
        super.startDocument();
        messages = new ArrayList<Message>();
        builder = new StringBuilder();
    }

    @Override
    public void startElement(String uri, String localName, String name,
            Attributes attributes) throws SAXException {
        super.startElement(uri, localName, name, attributes);
        if (localName.equalsIgnoreCase(ITEM)){
            this.currentMessage = new Message();
        }
    }
}
 
这是SAX处理的典型方式,处理简单的文档还是很方便。不过,如果xml结构变得复杂,上述方式就容易出错,
因为在处理标签的时候,我们需要知道该标签的结构层次,为此我们需要定义一些额外的实例变量(currentMessage),
android提供了SAX API的另一种使用方式,使得我们不需要写自己的handler:
public class AndroidSaxFeedParser extends BaseFeedParser {
    public AndroidSaxFeedParser(String feedUrl) {
        super(feedUrl);
    }

    public List<Message> parse() {
        final Message currentMessage = new Message();
        RootElement root = new RootElement("rss");
        final List<Message> messages = new ArrayList<Message>();
        Element channel = root.getChild("channel");
        Element item = channel.getChild(ITEM);

        item.setEndElementListener(new EndElementListener(){
            public void end() {
                messages.add(currentMessage.copy());
            }
        });

        item.getChild(TITLE).setEndTextElementListener(new EndTextElementListener(){
            public void end(String body) {
                currentMessage.setTitle(body);
            }
        });

        item.getChild(LINK).setEndTextElementListener(new EndTextElementListener(){
            public void end(String body) {
                currentMessage.setLink(body);
            }
        });

        // 其他字段省略

        try {
            Xml.parse(this.getInputStream(), Xml.Encoding.UTF_8, root.getContentHandler());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        return messages;
    }
}
 这种方式的特点是,你先手动建立xml的结构模型,然后在需要处理的节点上注册一个 EndTextElementListener。

方式二:使用DOM
DOM的特点是简单直观,处理小文档非常方便。它一次把文档读入内存,然后你可以用DOM API 来遍历文档,获取所需数据。当然,如果文档较大,它就比较耗内存了。
因此,在移动平台,你可以想象SAX比DOM使用得更普遍。
public class DomFeedParser extends BaseFeedParser {
    protected DomFeedParser(String feedUrl) {
        super(feedUrl);
    }

    public List<Message> parse() {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        List<Message> messages = new ArrayList<Message>();
        try {
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document dom = builder.parse(this.getInputStream());
            Element root = dom.getDocumentElement();
            NodeList items = root.getElementsByTagName(ITEM);
            for (int i=0;i<items.getLength();i++){
                Message message = new Message();
                Node item = items.item(i);
                NodeList properties = item.getChildNodes();
                for (int j=0;j<properties.getLength();j++){
                    Node property = properties.item(j);
                    String name = property.getNodeName();
                    if (name.equalsIgnoreCase(TITLE)){
                        message.setTitle(property.getFirstChild().getNodeValue());
                    } else if (name.equalsIgnoreCase(LINK)){
                        message.setLink(property.getFirstChild().getNodeValue());
                    } else if (name.equalsIgnoreCase(DESCRIPTION)){
                        StringBuilder text = new StringBuilder();
                        NodeList chars = property.getChildNodes();
                        for (int k=0;k<chars.getLength();k++){
                            text.append(chars.item(k).getNodeValue());
                        }
                        message.setDescription(text.toString());
                    } else if (name.equalsIgnoreCase(PUB_DATE)){
                        message.setDate(property.getFirstChild().getNodeValue());
                    }
                }
                messages.add(message);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        } 
        return messages;
    }
}

方式三:xml pull parser。

上面提到过StAX,android上面没有这个,但是xml pull parser是类似的东西,pull是拉的意思,为啥跟拉相关呢?首先,我们可以把SAX理解为--向handler不断”推送”事件,pull parser相反,它是从parse拉取或者说寻找事件:
 public class XmlPullFeedParser extends BaseFeedParser {
    public XmlPullFeedParser(String feedUrl) {
        super(feedUrl);
    }
    public List<Message> parse() {
        List<Message> messages = null;
        XmlPullParser parser = Xml.newPullParser();
        try {
            // auto-detect the encoding from the stream
            parser.setInput(this.getInputStream(), null);
            int eventType = parser.getEventType();
            Message currentMessage = null;

            boolean done = false;
            while (eventType != XmlPullParser.END_DOCUMENT && !done){
                String name = null;
                switch (eventType){
                    case XmlPullParser.START_DOCUMENT:
                        messages = new ArrayList<Message>();
                        break;

                    case XmlPullParser.START_TAG:
                        name = parser.getName();
                        if (name.equalsIgnoreCase(ITEM)){
                            currentMessage = new Message();
                        } else if (currentMessage != null){
                            if (name.equalsIgnoreCase(LINK)){
                                currentMessage.setLink(parser.nextText());
                            } else if (name.equalsIgnoreCase(DESCRIPTION)){
                                currentMessage.setDescription(parser.nextText());
                            } else if (name.equalsIgnoreCase(PUB_DATE)){
                                currentMessage.setDate(parser.nextText());
                            } else if (name.equalsIgnoreCase(TITLE)){
                                currentMessage.setTitle(parser.nextText());
                            }    
                        }
                        break;

                    case XmlPullParser.END_TAG:
                        name = parser.getName();
                        if (name.equalsIgnoreCase(ITEM) && currentMessage != null){
                            messages.add(currentMessage);
                        } else if (name.equalsIgnoreCase(CHANNEL)){
                            done = true;
                        }
                        break;
                }
                eventType = parser.next();
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return messages;
    }
}

 

 xml pull parser 比SAX多了一个循环,它不断调用parser.next()读取事件。值得注意的一点是,你可以随时终止while循环,比如你只需要读取到某一个节点时。

 

 

总结:

- android平台上,大多时候SAX是一个安全的选择

- 如果文档很小,DOM用起来更简单。

- 文档很大,并且你只需要文档的一部分,那么xml pull parser更高效。


 


0
1
分享到:
评论

相关推荐

    android xml解析1

    更为方便的是android SDK中提供了DefaultHandler和DefaultHandler2 来协助我们完成构建XML handler,事实上DefaultHandler本身实现了 ContentHander、DTDHander、ErrorHandler,以及EntityResolver这4个接口,相当于把...

    安卓调用WebService服务对返回的xml解析展示

    终于调通安卓调用Webservice,传参并解析XML的样例,使用工具:Android Studio和Eclipse.Eclipse启动WebServer,Android Studio进行Application编码调试。两个工程文件都在压缩包中。喜极而泣。。。

    android 使用Sax解析XML 源码实例

    下面是一个SAX解析XML的示例(有点长,因为详细注解了SAX事件处理的所有方法),SAX API中主要有四种处理事件的接口,它们分别是ContentHandler,DTDHandler, EntityResolver 和 ErrorHandler 。下面的例子可能...

    详解Android中解析XML的方法

    作为承载数据的一个重要角色,如何读写XML成为Android开发中一项重要的技能。今天就由我向大家介绍一下在Android平台下几种常见的XML解析和创建的方法。 在Android中,常见的XML解析器分别为SAX解析器、DOM解析器和...

    Android_和_XML_构建动态用户界面

    为更好地利用本文,您应该使用 Android SDK 来构造 Android ...在此过程中,您将创建自定义和动态的用户界面布局、多线程通信、消息处理程序、以及进程对话框。至少,您将了解 AndroidManifest.xml 和服务器端脚本编写

    Android xml反编译

    1.可视化界面操作 2.支持批量处理,选择一个目录即可 3.修复数组下标越界问题

    Android_XML_Demo:Android解析XML格式数据的三种方法

    作为承载数据的一个重要角色,如何读写XML成为Android开发中一项重要的技能。今天就由我向大家介绍一下在Android平台下几种常见的XML解析和创建的方法。 在Android中,常见的XML解析器分别为SAX解析器、DOM解析器和...

    Android自学笔记-9-Pull方式处理XML

    Android自学笔记-9-Pull方式处理XML

    android解析xml文件的方式

    在androd手机中处理xml数据时很常见的事情,通常在不同平台传输数据的时候,我们就可能使用xml,xml是与平台无关的特性,被广泛运用于数据通信中,那么在android中如何解析xml文件数据呢?通常有三种方式:DOM,SAX,...

    MT 2.10.3 反编译android xml等功能

    MT manage

    Android 让人人都懂XML解析,Pull方式解析Xml的详尽注释

    解析Xml有三种方式可选,sax ,dom ,pull ,,各有各的优点,但在android上是不推荐使用DOM来解析的 一般都用SAX和PULL 这两个性能相近, SAX的解析方式大家可以去看MARS的教程 讲的也比较好喔 PULL的话我个人觉得处理...

    Android 解析XML 文件的四种方法总结

    java解析xml文件四种方式 1.介绍 1)DOM(JAXP Crimson解析器) DOM是用与平台和语言无关的方式表示XML文档的...它还可以在任何时候在树中上下导航,而不是像SAX那样是一次性的处理。DOM使用起来也要简单得多。 2)S

    SAX--XML文件读写

    Android SDK只支持采用SAX技术读取XML,SAX采用顺序读取的方式来处理XML文档。这就要求在每读取XML文档的某个节点时会触发相应的事件来处理这个节点。下面基于一个实例讲述SAX的使用

    VectorDrawable2Svg:将Android VectorDrawable .xml文件转换为.svg文件

    此存储库是从派生的,以添加对间接颜色引用的处理(例如,在color.xml文件中),因为该存储库似乎没有得到积极维护(基于未解决的问题和merge /当时将请求拉到那里)。 用法 python3 VectorDrawable2Svg.py a.xml b...

    基于Android XML解析与保存的实现

    解析XML文件:在Android平台上可以使用SAX、DOM和Android附带的pull解析器解析XML文件;pull解析器提供了各种事件,使用parser.next()方法进入下一个元素并触发相应事件,pull解析器产生的事件是一个数字,可以通过...

    Node.js-用于将XML转换为JSON和JSON到XML的Android库

    用于将XML转换为JSON和JSON到XML的Android库

    android_通话处理流程

    1、contacts的androidmanifest.xml android:process="android.process.acore"说明此应用程序运行在acore进程中。 DialtactsActivity的intent-filter的action属性设置为main,catelog属性设置为launcher,所以此...

    android中用xml文件实现带边框背景效果的方法

    一般的,我们会让设计给做个背景图,然后自己用.9处理一下,这样有些麻烦,我们可以简洁点实现,就是用xml文件。 下面给出一个范例: &lt;?xml version=1.0 encoding=utf-8?&gt; &lt;layer-list xmlns:android=...

    Android Json数据处理

    Android Json数据处理 这里面的源码包括了PULL,SAX,DOM解析xml文件 还有一个是Json解析json文件的类

    Android 初学中阶高阶书籍_集合打包3

    段,Android 图像处理篇,Android_CTS测试研,GoogleMaps基础开发教程,Android_GPS架构分析,android_JNI编程_一些技 巧,android_jni操作指南,Android_NDK开发实例,Android_RIL层剖析(官方翻译),Android2.2+API+中文...

Global site tag (gtag.js) - Google Analytics