2011年8月27日 星期六

[Android 範例代碼] 使用 XML SAX Parser


轉載自 這裡
前言 :
這篇文章使用 SAX 來解析 XML 格式文件. 在 Android SDK 開發環境跟 XML 有關的方法有 SAX 與 DOM 兩種. 使用 DOM 解析器在開始工作前會先載進整個文件到記億體, 而在手機或終端裝置記億體比較嚴苛環境下往往會造成拖慢速度或記憶體不足的元凶. 使用 DOM 的好處是相對於 SAX 來講, 在解析文件時可以寫相對少的代碼. 但這裡我們的範例將使用 SAX, 原因是我們的開發環境對記億體較講究, 且使用 SAX 我們可以客制需要解析文件的部分並過濾不需要的相關訊息來加快處理的速度.

使用 XML SAX Parser :
考慮我們有 XML 檔案內容如下 :

接著我們要在 Activity 中處理該 xml 檔案, 首先我們要定義一個類別 Data 來存放我們解析出 XML 檔中有興趣的欄位或訊息 :
- Data.java :
  1. public class Data {   
  2.   // I know this could be an int, but this is just to show you how it works   
  3.   public String sectionId;   
  4.   public String section;   
  5.   public String area;   
  6.   
  7.   public Data() {   
  8.   
  9.   }   
  10. }  

接著 SAX (參考 XMLReader) 支援從 URI 直接 Streaming 動態解析 XML 或是從檔案讀取 XML 內容進行解析. 這裡我們因為將 xml 存放與檔案中, 故使用第二種方法. 在解析之前我們還必須定義一個類別或 Handler (DataHandler). 用來當作 XMLReader 的回呼函式. 在回呼函式中每當 Parser 解析完一個 Document 或 Element 便會透過對應的回呼函式 ( startElement() , endElement() etc ) 通知我們進行處理, 這時我們便可以取出有興趣的 Element 並過濾掉不需要的 Element. 而該類別或 Handler 需繼承 DefaultHandler 類別. 相關代碼如下 :
- DataHandler.java :
  1. public class DataHandler extends DefaultHandler {   
  2.   
  3.   // booleans that check whether it's in a specific tag or not   
  4.   private boolean _inSection, _inArea;   
  5.   
  6.   // this holds the data   
  7.   private Data _data;   
  8.   
  9.   /**  
  10.    * Returns the data object  
  11.    *  
  12.    * @return  
  13.    */   
  14.   public Data getData() {   
  15.     return _data;   
  16.   }   
  17.   
  18.   /**  
  19.    * This gets called when the xml document is first opened  
  20.    *  
  21.    * @throws SAXException  
  22.    */   
  23.   @Override   
  24.   public void startDocument() throws SAXException {   
  25.     _data = new Data();   
  26.   }   
  27.   
  28.   /**  
  29.    * Called when it's finished handling the document  
  30.    *  
  31.    * @throws SAXException  
  32.    */   
  33.   @Override   
  34.   public void endDocument() throws SAXException {   
  35.   
  36.   }   
  37.   
  38.   /**  
  39.    * This gets called at the start of an element. Here we're also setting the booleans to true if it's at that specific tag. (so we  
  40.    * know where we are)  
  41.    *  
  42.    * @param namespaceURI  
  43.    * @param localName  
  44.    * @param qName  
  45.    * @param atts  
  46.    * @throws SAXException  
  47.    */   
  48.   @Override   
  49.   public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {   
  50.   
  51.     if(localName.equals("section")) {   
  52.       _inSection = true;   
  53.   
  54.       _data.sectionId = atts.getValue("id");   
  55.     } else if(localName.equals("area")) {   
  56.       _inArea = true;   
  57.     }   
  58.   }   
  59.   
  60.   /**  
  61.    * Called at the end of the element. Setting the booleans to false, so we know that we've just left that tag.  
  62.    *  
  63.    * @param namespaceURI  
  64.    * @param localName  
  65.    * @param qName  
  66.    * @throws SAXException  
  67.    */   
  68.   @Override   
  69.   public void endElement(String namespaceURI, String localName, String qName) throws SAXException {   
  70.     Log.v("endElement", localName);   
  71.   
  72.     if(localName.equals("section")) {   
  73.       _inSection = false;   
  74.     } else if(localName.equals("area")) {   
  75.       _inArea = false;   
  76.     }   
  77.   }   
  78.   
  79.   /**  
  80.    * Calling when we're within an element. Here we're checking to see if there is any content in the tags that we're interested in  
  81.    * and populating it in the Config object.  
  82.    *  
  83.    * @param ch  
  84.    * @param start  
  85.    * @param length  
  86.    */   
  87.   @Override   
  88.   public void characters(char ch[], int start, int length) {   
  89.     String chars = new String(ch, start, length);   
  90.     chars = chars.trim();   
  91.   
  92.     if(_inSection) {   
  93.       _data.section = chars;   
  94.     } else if(_inArea) {   
  95.       _data.area = chars;   
  96.     }   
  97.   }   
  98. }  

最後要做的就是在 Activity 類別使用上述客製化過的類別與 SAX 套件來處理 XML 解析, 部分代碼如下 :
- Activity 部分代碼 :
  1. @Override   
  2. public void onCreate(Bundle icicle) {   
  3.   super.onCreate(icicle);   
  4.   setContentView(R.layout.main);   
  5.   
  6.   
  7.   // start the parser and get back the Data object, which you can do whatever you want with   
  8.   Data data = _parseXml();   
  9. }   
  10.   
  11. private Data _parseXml() {   
  12.   Data data = null;   
  13.   
  14.   // sax stuff   
  15.   try {   
  16.     SAXParserFactory spf = SAXParserFactory.newInstance();   
  17.     SAXParser sp = spf.newSAXParser();   
  18.   
  19.     XMLReader xr = sp.getXMLReader();   
  20.   
  21.     DataHandler dataHandler = new DataHandler();   
  22.     xr.setContentHandler(dataHandler);   
  23.   
  24.     xr.parse(new InputSource(new FileInputStream("/path/to/data.xml")));   
  25.   
  26.     data = dataHandler.getData();   
  27.   
  28.   } catch(ParserConfigurationException pce) {   
  29.     Log.e("SAX XML""sax parse error", pce);   
  30.   } catch(SAXException se) {   
  31.     Log.e("SAX XML""sax error", se);   
  32.   } catch(IOException ioe) {   
  33.     Log.e("SAX XML""sax parse io error", ioe);   
  34.   }   
  35.   
  36.   return data;   
  37. }  

上面代碼首先透過Singleton模式 SAXParserFactory.newInstance() 取的 SAX Parser 的工廠並接著取得 XMLReader. 接著將剛剛我們撰寫的 Handle/回呼函式 傳進去當作解析過程中抽取我們有興趣的訊息. 解析完畢後, 我們並透過 Handler (DataHandler) 的函式 getData() 取回剛剛我們用來存放有興趣資訊的類別, 最後一步便是根據需求來處理這些資訊. (例如如果有 GUI, 便可以使用 TextView.setText() 將之顯示出來).

補充說明 :
android xml parser 如何從網路下載XML並解析
Android XML Parsing Tutorial – Using DOMParser
Moving ahead from Android XML Parsing using SAXParser, here we are going to see about how to parse a XML using DOM Parser...
This message was edited 8 times. Last update was at 27/08/2011 22:59:45

2 則留言:

  1. DataHandler.java 第14行 好像是要 public Data getData() { 的樣子? 請幫忙確認看看 XD

    回覆刪除

[Git 常見問題] error: The following untracked working tree files would be overwritten by merge

  Source From  Here 方案1: // x -----删除忽略文件已经对 git 来说不识别的文件 // d -----删除未被添加到 git 的路径中的文件 // f -----强制运行 #   git clean -d -fx 方案2: 今天在服务器上  gi...