Android XML讀寫(五)
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;
- }
- }