1

我需要编写一个 XML 解析类,我可以在整个 Android 应用程序中重用它,并且从我读过的内容来看,SAXParser 是移动应用程序的最佳选择。我正在使用本指南:

http://www.jondev.net/articles/Android_XML_SAX_Parser_Example

我希望解析的文档类型是来自 Blogger GData API 的提要 - 例如:

<?xml version='1.0' encoding='UTF-8'?>
<?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?>
<feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearch/1.1/' xmlns:gd='http://schemas.google.com/g/2005' gd:etag='W/&quot;CUIGRnc4fyp7ImA9Wx9SEEg.&quot;'>
    <id>tag:blogger.com,1999:user-464300745974.blogs</id>
    <updated>2010-11-29T17:58:47.937Z</updated>
    <title>Tim's Blogs</title>
    <link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://www.blogger.com/feeds/blogid/blogs'/>
    <link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/blogid/blogs'/>
    <link rel='alternate' type='text/html' href='http://www.blogger.com/profile/blogid'/>
    <author>
        <name>Tim</name>
        <uri>http://www.blogger.com/profile/blogid</uri>
        <email>noreply@blogger.com</email>
    </author>
    <generator version='7.00' uri='http://www.blogger.com'>Blogger</generator>
    <openSearch:totalResults>2</openSearch:totalResults>
    <openSearch:startIndex>1</openSearch:startIndex>
    <openSearch:itemsPerPage>25</openSearch:itemsPerPage>
    <entry gd:etag='W/&quot;DUIBQHg-cCp7ImA9Wx9TF0s.&quot;'>
        <id>tag:blogger.com,1999:user-464300745974.blog-blogid</id>
        <published>2010-06-22T10:59:38.603-07:00</published>
        <updated>2010-11-26T02:32:31.658-08:00</updated>
        <title>Application Testing Blog</title>
        <summary type='html'>This blog is for testing the Android application.</summary>
        <link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/blogid/blogs/blogid'/>
        <link rel='alternate' type='text/html' href='http://devrum.blogspot.com/'/>
        <link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://devrum.blogspot.com/feeds/posts/default'/>
        <link rel='http://schemas.google.com/g/2005#post' type='application/atom+xml' href='http://www.blogger.com/feeds/blogid/posts/default'/>
        <link rel='http://schemas.google.com/blogger/2008#template' type='application/atom+xml' href='http://www.blogger.com/feeds/blogid/template'/>
        <link rel='http://schemas.google.com/blogger/2008#settings' type='application/atom+xml' href='http://www.blogger.com/feeds/blogid/settings'/>
        <author>
            <name>Tim</name>
            <uri>http://www.blogger.com/profile/blogid</uri>
            <email>noreply@blogger.com</email>
        </author>
    </entry>
    <entry gd:etag='W/&quot;C08HRXo4eSp7ImA9Wx9TE0o.&quot;'>
        <id>tag:blogger.com,1999:user-464300745974.blog-515600026106499737</id>
        <published>2010-06-22T10:59:00.328-07:00</published>
        <updated>2010-11-21T12:37:14.431-08:00</updated>
        <title>Development Blog</title>
        <summary type='html'>etc</summary>
        <link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/blogid/blogs/515600026106499737'/>
        <link rel='alternate' type='text/html' href='http://rumdev.blogspot.com/'/>
        <link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://rumdev.blogspot.com/feeds/posts/default'/>
        <link rel='http://schemas.google.com/g/2005#post' type='application/atom+xml' href='http://www.blogger.com/feeds/515600026106499737/posts/default'/>
        <link rel='http://schemas.google.com/blogger/2008#template' type='application/atom+xml' href='http://www.blogger.com/feeds/515600026106499737/template'/>
        <link rel='http://schemas.google.com/blogger/2008#settings' type='application/atom+xml' href='http://www.blogger.com/feeds/515600026106499737/settings'/>
        <author>
            <name>Tim</name>
            <uri>http://www.blogger.com/etc</uri>
            <email>noreply@blogger.com</email>
        </author>
    </entry>
</feed>

我需要从上面的提要中解析博客 ID 和发布 ID。从我在 SAX 上找到的任何示例来看,它们根本不是通用的。我想写一个可重用的,你有什么例子我可以相应地修改 SAXParser 吗?

4

2 回答 2

3

SAX 解析器是事件驱动的解析器。您为每个类型的 XML 节点(开始元素、结束元素、属性、文本等)编写一个处理程序,然后解析器迭代 XML 文档并将 SAX 事件发送给您(= 调用处理程序中的方法)。

在您的特定情况下,您正在寻找两个节点序列:

  1. <feed><id>
  2. <feed><entry><id>

所以你必须在你的处理程序中存储一些状态信息才能知道你在哪里。这是代码(自己没有尝试过,你必须调试它):

public class DataHandler extends DefaultHandler {

    private Feed feed;
    private Entry currentEntry;
    private boolean isId = false;

    public Feed getFeed() {
        return feed;
    }

    @Override
    public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
        if (localName.equals("feed")) {
            feed = new Feed();
        } else if (localName.equals("entry")) {
            currentEntry = new Entry();
        } else if (localName.equals("id")) {
            isId = true;
        }
    }

    @Override
    public void endElement(String namespaceURI, String localName, String qName) throws SAXException {
        if (localName.equals("feed")) {
            // </feed> - do nothing, it's the end
        } else if (localName.equals("entry")) {
            // </entry> - save current entry and reset variable
            feed.entries.add(currentEntry);
            currentEntry = null;
        } else if (localName.equals("id")) {
             isId = false;
        }
    }

    @Override
    public void characters(char ch[], int start, int length) {
        if(!isId) return;

        String chars = new String(ch, start, length);
        chars = chars.trim();

        if (currentEntry != null) {
            currentEntry.id = chars;
        } else {
            feed.id = chars;
        }
    }

    private class Feed {
        public String id;
        public List<Entry> entries = new ArrayList<Entry>();
    }

    private class Entry {
        public String id;
    }
}
于 2011-02-28T15:33:14.233 回答
1

尝试这样的事情:

public class XmlParser extends DefaultHandler{
    private static final int        STATE_FEED      = 0;
    private static final int        STATE_ID        = 1;
    private static int          sDepth          = 0;
    private static int          sCurrentState   = 0;
    private String              mTheString;
public XmlParser(){}

@Override
public void startDocument() throws SAXException{}

@Override
public void endDocument() throws SAXException{}

@Override
public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException{
    mTheString = "";
    sDepth++;
    if (qName.equals("feed")){
        sCurrentState = STATE_FEED;
        return;
    }
    if (qName.equals("id")){
                    sCurrentState = STATE_ID;
            return;
    }
    sCurrentState = 0;
}

@Override
public void endElement(String namespaceURI, String localName, String qName) throws SAXException{
    sDepth--;
        switch (sCurrentState){
            case STATE_FEED:
                                   //Do something with the feed
                sCurrentState = 0;
                mTheString = "";
                break;
            case STATE_ID:
                // Save the ID or do whatever
                sCurrentState = 0;
                mTheString = "";
                break;
            default:
                //Do nothing
                mTheString = "";
                return;
        }
        mTheString = "";
}

@Override
public void characters(char ch[], int start, int length){
      mTheString = mTheString + new String(ch, start, length);
}

}

您可以通过以下方式访问自定义 SAXParser:

InputStream stream = //whatever your stream is (the document)
XmlParser handler = new XmlParser(); // your custom parser
XMLReader xmlreader = XMLReaderFactory.createXMLReader();
xmlreader.setContentHandler(handler); 
xmlreader.parse(new InputSource(stream));
   // Then you can create a method in the handler, like getResults to return the list of elements or something here.

因此,您将自定义解析器传递给 Xml Reader,并从源代码中获取结果。在 Xml 解析期间,处理程序从“开始文档”开始,然后遍历 xml 中的元素(在开始时调用 startElement,在开始时调用 endElement)。characters 方法在这两者之间被调用 - 拾取字符(然后你可以在 endElement 中做任何你想做的事情)。解析器在调用 endDocument 时完成,因此您可以根据需要在元素的开头和结尾或整个文档中设置和删除它们。

希望这会有所帮助,并且接近您想要做的事情。

于 2011-02-28T15:42:21.750 回答