XML 解析器
Java 的 Simple API for XML (SAX) 和 Document Object Model (DOM) 在 Android 上都是可用的。这些 API 多年以来一直都是 Java 技术的一部分。较新的 Streaming API for XML (StAX) 在 Android 中并不可用。但是, Android 提供了一个功能相当的库。最后,Java XML Binding API 在 Android 中也不可用。这个 API 已确定可以在 Android 中实现。但是,它更倾向于是一个重量级的 API,需要使用许多不同类的实例来表示 XML 文档。因此,这对于受限的环境,比如说 Android 针对的手持设备,不太理想。

基本提要解析器类
public abstract class BaseFeedParser implements FeedParser {    // names of the 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);        }    }}


示例 XML 提要
<?xml version="1.0" encoding="UTF-8"?><!-- generator="FeedCreator 1.7.2" --><rss version="2.0">      <channel>            <title>android_news</title>               <description>android_news</description>            <link>http://www.androidster.com/android_news.php</link>            <lastBuildDate>Sun, 19 Apr 2009 19:43:45 +0100</lastBuildDate>            <generator>FeedCreator 1.7.2</generator>            <item>                  <title>Samsung S8000 to Run Android, Play DivX, Take Over the World</title>                   <link>http://www.androidster.com/android_news/samsung-s8000-to-run-android-play-divx-take-over-the-world</link>                  <description>More details have emerged on the first Samsung handset to run Android. 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>After months of discovery and hearsay, the Android build that we have 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>


使用 SAX

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);        }     }}



SAX 处理程序
import static org.developerworks.android.BaseFeedParser.*;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();        }    }}


Android SDK 提供了一个名称为 android.util.Xml 的实用类. Android SAX 解析器
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();    }}


经过简化的 Android SAX 解析器
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);            }        });        item.getChild(DESCRIPTION).setEndTextElementListener(new EndTextElementListener(){            public void end(String body) {                currentMessage.setDescription(body);            }        });        item.getChild(PUB_DATE).setEndTextElementListener(new EndTextElementListener(){            public void end(String body) {                currentMessage.setDate(body);            }        });        try {            Xml.parse(this.getInputStream(), Xml.Encoding.UTF_8, root.getContentHandler());        } catch (Exception e) {            throw new RuntimeException(e);        }        return messages;    }}

新的 SAX 解析代码并未使用 SAX 处理程序,而是使用了 SDK 中的 android.sax 包中的类。这些类允许您构建 XML 文档的结构,并根据需要添加事件监听程序。在以上代码中,您声明文档将有一个 rss 根元素,并且它有一个 channel 子元素。然后,您声明 channel 将有一个 ITEM 子元素,并且开始添加监听程序。对于每个监听程序,您都使用了一个实现了特定接口(EndElementListner 或 EndTextElementListener)的匿名内部类。注意,您不需要跟踪字符数据。不仅仅因为这样会更加简单,更重要的是更加高效。最后,在调用 Xml.parse 实用方法时,您将传递一个通过根元素生成的处理程序

使用 DOM
基于 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 解析器
Android 并未提供对 Java StAX API 的支持。但是,Android 确实附带了一个 pull 解析器,其工作方式类似于 StAX。它允许您的应用程序代码从解析器中获取事件,这与 SAX 解析器自动将事件推入处理程序相反
基于 Pull 解析器的实现
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;    }}

pull 解析器的运行方式与 SAX 解析器相似。它提供了类似的事件(开始元素和结束元素),但您需要使用 (parser.next() 提取它们。事件将作为数值代码被发送,因此您可以使用一个简单 case-switch。注意,解析并未像 SAX 解析那样监听元素的结束,而是在开始处完成了大部分处理。在代码中,当某个元素开始时,您可以调用 parser.nextText() 从 XML 文档中提取所有字符数据。还需注意,您设置了一个标记(布尔变量 done)来确定何时到达感兴趣内容的结束部分。这允许您提早停止读取 XML 文档,因为您知道代码将不会关心文档的其余部分。这有时非常实用,特别是当您只需要访问一小部分 XML 文档时。通过尽快停止解析,您可以极大地减少解析时间。这种优化对于连接速度较慢的移动设备尤为重要。pull 解析器可以提供一些性能优势以及易用性。它还可以用于编写 XML。


创建 XML
使用 pull 解析器编写 XML
private String writeXml(List<Message> messages){    XmlSerializer serializer = Xml.newSerializer();    StringWriter writer = new StringWriter();    try {        serializer.setOutput(writer);        serializer.startDocument("UTF-8", true);        serializer.startTag("", "messages");        serializer.attribute("", "number", String.valueOf(messages.size()));        for (Message msg: messages){            serializer.startTag("", "message");            serializer.attribute("", "date", msg.getDate());            serializer.startTag("", "title");            serializer.text(msg.getTitle());            serializer.endTag("", "title");            serializer.startTag("", "url");            serializer.text(msg.getLink().toExternalForm());            serializer.endTag("", "url");            serializer.startTag("", "body");            serializer.text(msg.getDescription());            serializer.endTag("", "body");            serializer.endTag("", "message");        }        serializer.endTag("", "messages");        serializer.endDocument();        return writer.toString();    } catch (Exception e) {        throw new RuntimeException(e);    } }


XmlSerializer 类是上面用pull解析xml所使用的 XmlPullParser 包的一部分。它没有提取事件,而是将它们推出到数据流或编写程序中。在本例中,它仅仅将事件推送到了一个 java.io.StringWriter 实例中。它提供了一个直观的 API,通过各种方法开始和结束文档、处理元素以及添加文本或属性。这是 StringBuilder 的一种出色的替换方案,因为它可以更加轻松地确保您的 XML 具有良好结构。

更多相关文章

  1. 转:LinearLayout布局
  2. Android安全机制解析与应用实践
  3. android layout属性介绍
  4. android 处理运行时改变 开发文档翻译
  5. Android(安卓)AbsListView坐标体系解析
  6. 常用的一些属性说明
  7. android 处理运行时改变 开发文档翻译
  8. Android(安卓)UI布局之LinearLayout
  9. android 相对布局属性说明

随机推荐

  1. Mac下Android相关配置
  2. 5款 Android 3.0 平板電腦採購推薦
  3. Android(安卓)ApiDemos示例解析(122):Vie
  4. 百度抢滩LBS服务 身边Android版客户端正
  5. android adb install + apk 与adb push+a
  6. Android(安卓)TextView 中设置text的格式
  7. android关于uses-permission权限列表
  8. libjpeg-turbo 编译 android,ios,linux,w
  9. Android 页面销毁、重建与数据恢复
  10. Android 利用控件显示HTML样式