1. 程式人生 > >Android 建立與解析XML

Android 建立與解析XML

Android 是最常用的智慧手機平臺,XML 是資料交換的標準媒介,Android 中可以使用標準的XML生成器、解析器、轉換器 API,對 XML 進行解析和轉換。

XML,相關有DOM、SAX、JDOM、DOM4J、Xerces、JAXP等一堆概念,但是很多人總是會弄混他們之間的關係,這對我們理解XML檔案的建立和解析很不利。要挑選一個適合在Android平臺上使用的XML解析方案,我們還是得先把這些概念釐清。

XML基本概念

DOM(Document Object Model,文件物件模型)和SAX(Simple API for XML,簡單XML應用介面),是JAXP(Java API for XML Processing,Java XML處理的應用介面)定義的2種不同的對XML文件進行分析、處理的方法。

DOM方法是用標準物件模型表示 XML 文件;SAX方法則使用事件模型來處理程式來處理XML。

JAXP完成了對SAX、DOM的包裝,它嚮應用程式提供針對DOM的DocumentBuilderFactory、 DocumentBuilder;以及針對SAX的SAXParserFactory、SAXParser抽象工廠類。在Jave SE中JAXP對應javax.xml.parsers包,DOM對應org.w3c.dom,SAX對應org.xml.sax。


Xerces首先繼承並實現了javax.xml.parser包內的SAXParser、SAXParserFactory、DocumentBuilder、DocumentBuilderFactory等抽象類,並提供了JAXP中所定義的DOM、SAX(以及StAX,後面會介紹)這些XML解析方法的實現和相應的Parser。

JDOM

DOM4J,是因為有人覺得W3C的DOM標準API太過難用而著手開發的替代API,它們和JAXP一樣都是對DOM、SAX的封裝,不過JDOM、DOM4J做了更多的事情,相當於上面提到JAXP介面+Xerces DOM實現部分。JDOM並沒有自己開發Parser,所以還是需要利用Xerces的Parser部分,而DOM4J自帶一個名為Alfred2的Parser,當然也可以使用Xerces的Parser。看起來JAXP具備更好的可移植性,即我們可以通過修改配置檔案切換不同的DOM實現和SAX、DOM Parser,JDOM、DOM4J雖然也可以切換Parser,但是DOM實現是無法切換的。(參考: 
Java XML API 漫談
  和  JAXP全面介紹

XML建立與解析

XML建立主要四種方式:Dom、Sax、Pull、Dom4j

XML解析主要四種方式:Dom、Sax、Pull、Dom4j

其中,利用Dom、Sax、Pull、Dom4j建立的標準XML格式檔案,可以由任何一種Dom、Sax、Pull、Dom4j解析方式進行解析。


Android中解析XML

DOM解析器,是通過將XML文件解析成樹狀模型並將其放入記憶體來完成解析工作的,然後對文件的操作都是在這個樹狀模型上完成的。這個在記憶體中的文件樹將是文件實際大小的幾倍。這樣做的好處是結構清晰、操作方便,而帶來的麻煩就是極其耗費系統資源。

SAX解析器,正好克服了DOM的缺點,分析能夠立即開始,而不是等待所有的資料被處理。而且,由於應用程式只是在讀取資料時檢查資料,因此不需要將資料儲存在記憶體中,這對於大型文件來說是個巨大的優點。事實上,應用程式甚至不必解析整個文件,它可以在某個條件得到滿足時停止解析。

DOM與SAX比較

下面的表格列出了SAX和DOM在一些方面的對照:

SAXDOM
順序讀入文件併產生相應事件,可以處理任何大小的XML文件在記憶體中建立文件樹,不適於處理大型XML文件。
只能對文件按順序解析一遍,不支援對文件的隨意訪問。可以隨意訪問文件樹的任何部分,沒有次數限制。
只能讀取XML文件內容,而不能修改可以隨意修改文件樹,從而修改XML文件。
開發上比較複雜,需要自己來實現事件處理器。易於理解,易於開發。
對開發人員而言更靈活,可以用SAX建立自己的XML物件模型。已經在DOM基礎之上建立好了文件樹。

通過對SAX和DOM的分析,它們各有自己的不同應用領域:

SAX適於處理下面的問題:
  1. 對大型文件進行處理。
  2. 只需要文件的部分內容,或者只需要從文件中得到特定資訊。
  3. 想建立自己的物件模型的時候。

DOM適於處理下面的問題:

  1. 需要對文件進行修改
  2. 需要隨機對文件進行訪問,例如XSLT解析器。
DOM和SAX的應用場景
1、資料修改:如果打算對資料作出更改並將它輸出為 XML,那麼在大多數情況下,DOM 是適當的選擇。並不是說使用 SAX 就不能更改資料,但是該過程要複雜得多,因為您必須對資料的一份拷貝而不是對資料本身作出更改。
2、資料容量: 對於大型檔案,SAX 是更好的選擇。
3、資料使用:如果只有資料中的少量部分會被使用,那麼使用 SAX 來將該部分資料提取到應用程式中可能更好。 另一方面,如果您知道自己以後會回頭引用已處理過的大量資訊,那麼 SAX 也許不是恰當的選擇。
4、速度要求: SAX 實現通常要比 DOM 實現速度更快
基於上面的分析,在基於Android系統的記憶體和CPU資源比較有限的手持裝置上,只要我們不需要修改XML資料或者隨機的訪問XML資料,SAX儘管可能需要更多的編碼工作,但是為了更小的記憶體和CPU消耗,還是值得的。

另外,Android SDK中已經包含了JAXP對應的javax.xml.parsers包,SAX對應org.xml.sax,DOM對應的org.w3c.dom包,加上Android還提供了android.sax這樣的包來方便SAX Handle的開發,基於JAXP和SAX這樣的標準方法來開發不僅複雜度不高,即使出現問題在討論組中尋求解決方案也是比較容易的。(參考: 使用 SAX 處理 XML 文件   和   DOM SAX JAXP DOM4J JDOM xerces解析器

Android中解析XML實現

基於上面的分析,採用JAXP+SAX的方案是我比較看好的。我們首先需要又一個SAXParserFactory的例項,然後從工廠中得到一個SAXParser例項,進而獲取一個XMLReader;接下來新建一個Handler類繼承自SAX Helpler的DefaultHandler,並實現startDocument()、startElement()、endElement()以及endDocument()等方法,並把這個Handler作為XMLReader的Content Handler;最後以帶解析的XML文件為引數呼叫XMLReader的parse方法即可。具體的程式碼參考:Android 上使用 XML  和  Android 3.0 平臺上建立和解析 XML

1、Android系統中的DOM和SAX實現
Android SDK中包含了JAXP對應javax.xml.parsers包,SAX對應的org.xml.sax,DOM對應的org.w3c.dom包,所以我們就已經有了XML解析所需的JAXP——對SAX和DOM的封裝(抽象類)以及SAX和DOM介面類,但是對於JAXP抽象類的實現,以及DOM和SAX介面類的實現在哪裡呢?是和Java SE 5.0一樣用了Xerces嗎? 不!
通過檢視Android 1.5的原始碼,我看到這部分的程式碼來自Apache Harmony這個開源的Java SE實現,位於./dalvik/libcore/xml/src/main/java/org/apache/harmony/xml目錄。這裡包含有一個完整的DOM實現(dom目錄),對於javax.xml.parser下的抽象類的實現(parser目錄),以及對於SAX介面類的實現(除此以外還包括對XMLPullParser介面的實現)。

2、XmlPull 和 KXML2
XmlPull解析器,提供了資源有限的環境(如J2ME)應用使用的XML解析API,XPP提供了非常簡單的介面——包含一個介面、一個異常、一個建立解析器的factory。它採用了類似JAXP的工廠模式,把介面設計和實現分離,KXML2就是一個為J2ME環境優化的一個實現。在Android SDK中,已經包含了XmlPull(org.xmlpull.v1包)以及它的一個AddOn——SAX2 Driver——它使得我們可以通過SAX2的API來操縱XmlPull Parser。另外,通過sourcecode,我們可以看到Android SDK中的XmlPull的實現是KXML2,位於./dalvik/libcore/xml/src/main/java/org/kxml2目錄。Apache Harmony的目錄中同樣有一個ExpatPullParser類實現了XMLPullParser介面,但是卻沒有XmlSerializer介面的實現,所以只能說Android中的Harmony也部分實現了XmlPull API。XmlPull+KXML2是下一步我要實踐的方案,到時候還得學習一下如何“公平”的比較兩者的效能。

3、StAX

儘管Android中還沒有提供相應的支援,但是Streaming API for XML (StAX) 作為用Java語言處理 XML的最新標準,無論從效能還是可用性上都有出色的表現。它不僅提供了一個快捷、易用、佔用記憶體少的 XML 解析器,它還提供了過濾器介面,允許程式設計師嚮應用程式業務邏輯隱藏不需要的文件細節。感興趣的朋友可以看一看下面的文章。

參考推薦:


 3888人閱讀 評論(0) 收藏 舉報

1. Dom概述

Dom方式建立XML,應用了標準xml構造器 javax.xml.parsers.DocumentBuilder 來建立 XML 文件,需要匯入以下內容

javax.xml.parsers

javax.xml.parsers.DocumentBuilder 

javax.xml.parsers.DocumentBuilderFactory 

javax.xml.parsers.ParserConfigurationException;

javax.xml.transform

javax.xml.transform.TransformerFactory 

javax.xml.transform.Transformer 

javax.xml.transform.dom.DOMSource 

javax.xml.transform.stream.StreamResult 

javax.xml.transform.OutputKeys;

javax.xml.transform.TransformerFactoryConfigurationError;

javax.xml.transform.TransformerConfigurationException;

javax.xml.transform.TransformerException;

org.w3c.dom 

org.w3c.dom.Document;

org.w3c.dom.Element;

org.w3c.dom.Node;

org.w3c.dom.DOMException;

org.w3c.dom.NodeList;

org.xml.sax.SAXException;

建立和解析xml的效果圖:


2、Dom 建立 XML

Dom,藉助 javax.xml.parsers.DocumentBuilder,可以建立 org.w3c.dom.Document 物件。

使用來自 DocumentBuilderFactory 的 DocumentBuilder 物件在 Android 裝置上建立與解析 XML 文件。您將使用 XML pull 解析器的擴充套件來解析 XML 文件。

Code

[java] view plaincopyprint?
  1. /** Dom方式,建立 XML  */
  2. public String domCreateXML() {  
  3.     String xmlWriter = null;  
  4.     Person []persons = new Person[3];       // 建立節點Person物件
  5.     persons[0] = new Person(1"sunboy_2050""http://blog.csdn.net/sunboy_2050");  
  6.     persons[1] = new Person(2"baidu""http://www.baidu.com");  
  7.     persons[2] = new Person(3"google""http://www.google.com");  
  8.     try {  
  9.         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();  
  10.         DocumentBuilder builder = factory.newDocumentBuilder();  
  11.         Document doc = builder.newDocument();  
  12.         Element eleRoot = doc.createElement("root");  
  13.         eleRoot.setAttribute("author""homer");  
  14.         eleRoot.setAttribute("date""2012-04-26");  
  15.         doc.appendChild(eleRoot);  
  16.         int personsLen = persons.length;  
  17.         for(int i=0; i<personsLen; i++) {  
  18.             Element elePerson = doc.createElement("person");  
  19.             eleRoot.appendChild(elePerson);  
  20.             Element eleId = doc.createElement("id");  
  21.             Node nodeId = doc.createTextNode(persons[i].getId() + "");  
  22.             eleId.appendChild(nodeId);  
  23.             elePerson.appendChild(eleId);  
  24.             Element eleName = doc.createElement("name");  
  25.             Node nodeName = doc.createTextNode(persons[i].getName());  
  26.             eleName.appendChild(nodeName);  
  27.             elePerson.appendChild(eleName);  
  28.             Element eleBlog = doc.createElement("blog");  
  29.             Node nodeBlog = doc.createTextNode(persons[i].getBlog());  
  30.             eleBlog.appendChild(nodeBlog);  
  31.             elePerson.appendChild(eleBlog);  
  32.         }  
  33.         Properties properties = new Properties();  
  34.         properties.setProperty(OutputKeys.INDENT, "yes");  
  35.         properties.setProperty(OutputKeys.MEDIA_TYPE, "xml");  
  36.         properties.setProperty(OutputKeys.VERSION, "1.0");  
  37.         properties.setProperty(OutputKeys.ENCODING, "utf-8");  
  38.         properties.setProperty(OutputKeys.METHOD, "xml");  
  39.         properties.setProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");  
  40.         TransformerFactory transformerFactory = TransformerFactory.newInstance();  
  41.         Transformer transformer = transformerFactory.newTransformer();  
  42.         transformer.setOutputProperties(properties);  
  43.         DOMSource domSource = new DOMSource(doc.getDocumentElement());  
  44.         OutputStream output = new ByteArrayOutputStream();  
  45.         StreamResult result = new StreamResult(output);  
  46.         transformer.transform(domSource, result);  
  47.         xmlWriter = output.toString();  
  48.     } catch (ParserConfigurationException e) {      // factory.newDocumentBuilder
  49.         e.printStackTrace();  
  50.     } catch (DOMException e) {                      // doc.createElement
  51.         e.printStackTrace();  
  52.     } catch (TransformerFactoryConfigurationError e) {      // TransformerFactory.newInstance
  53.         e.printStackTrace();  
  54.     } catch (TransformerConfigurationException e) {     // transformerFactory.newTransformer
  55.         e.printStackTrace();  
  56.     } catch (TransformerException e) {              // transformer.transform
  57.         e.printStackTrace();  
  58.     } catch (Exception e) {  
  59.         e.printStackTrace();  
  60.     }  
  61.     savedXML(fileName, xmlWriter.toString());  
  62.     return xmlWriter.toString();  
  63. }  

執行結果:


3、Dom 解析 XML

Dom方式,解析XML是建立XML的逆過程,主要用到了builder.parse(is)進行解析,然後通過Tag、NodeList、Element、childNotes等得到Element和Node屬性或值。

Code

[java] view plaincopyprint?
  1. /** Dom方式,解析 XML  */
  2. public String domResolveXML() {  
  3.     StringWriter xmlWriter = new StringWriter();  
  4.     InputStream is= readXML(fileName);  
  5.     try {  
  6.         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();  
  7.         DocumentBuilder builder = factory.newDocumentBuilder();  
  8.         Document doc = builder.parse(is);  
  9.         doc.getDocumentElement().normalize();  
  10.         NodeList nlRoot = doc.getElementsByTagName("root");  
  11.         Element eleRoot = (Element)nlRoot.item(0);