de >RssHandlerde > 类扩展了 de >org.xml.sax.helpers.DefaultHandlerde > 类。该类为 SAX 解析器生成的事件所对应的所有方法都提供了一个默认的非操作实现。这允许子类根据需要仅覆盖一些方法。de >RssHandlerde > 提供了一个额外的 API,即 de >getMessagesde >。它返回处理程序在从 SAX 解析器接收事件时所收集的 de >Messagede > 对象列表。它有另外两个内部变量,de >currentMessagede > 针对被解析的 de >Messagede > 实例,以及名称为 de >builderde > 的 de >StringBuilderde > 变量,用于存储文本节点中的字符数据。解析器将相应事件发送给处理程序时会调用 de >startDocumentde > 方法,这两个变量的初始化操作就是在此时完成。
查看de >startElementde > 方法。在XML文档中每次遇到开始标记时都会调用它。您只关心该标记何时为 de >ITEMde > 标记。对于这种情况,您将创建一个新的 de >Messagede >。现在来看 de >charactersde > 方法。遇到文本节点中的字符数据时便会调用此方法。数据只是被添加到 de >builderde > 变量中。***,我们来看 de >endElementde > 方法。遇到结束标记时会调用此方法。对于与某 de >Messagede > 属性相对应的标记,如 de >TITLEde > 和 de >LINKde >,则使用 de >builderde > 变量中的数据在 de >currentMessagede > 上设置适当的属性。如果结束标记是一个 de >ITEMde >,则 de >currentMessagede > 将被添加到 Messages 列表中。所有这些都是非常典型的 SAX 解析;此处的一切都不是 Android 所特有的。因此,如果您知道如何编写 Java SAX 解析器,则应该知道如何编写 Android SAX 解析器。但是,android sdk 确实在 SAX 上添加了一些便捷的特性。
Android SAX 解析器
java代码:
- 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 处理程序,因此您仅仅重用了所示的 de >RssHandlerde >。能够重用 SAX 处理程序是非常不错的,但其代码稍微有些复杂。您可以想像,如果需要解析一个更加复杂的 XML 文档,则处理程序可能会带来各种各样的 bug。举例来说,回头看看 de >endElementde > 方法。注意,在尝试设置属性之前,它检查了 de >currentMessagede > 是否为 null。现在,再回头看看示例 XML。 注意,de >ITEMde > 标记外部有一些 de >TITLEde > 和 de >LINKde > 标记。这就是使用 null 检查的原因。否则,每一个 de >TITLEde > 标记 会导致一个 de >NullPointerExceptionde >。Android 提供了自己独有的 SAX API,它排除了您编写自己的 SAX 处理程序的需要。
经过简化的 Android SAX 解析器
java代码:
- 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;
- }
- }