Android學習筆記(八)XML文檔的解析


一、廢話

  最近幾天四川一直下雨,冷!今天到成都的時候,下午3點多的天和晚上天差不多,黑呼呼的... ...難道傳說的2012來了?哈哈哈... ...

二、正文  

  在上一篇筆記中提到過說在Android系統中,存儲數據的方式除了SQLite外,還有很多其他的方式,比較常用的就是XML方式。在Android中,比較常用的XML解析方式有SAX方式和DOM方式。下面就來看看這兩種方式吧。

1、 SAX解析

  SAX——Simple API for XML,在org.xml.sax包中被提供使用。SAX是基於事件驅動的,有事件就一定有事件源,這個事件源就是SAX解析XML時的一個XMLReader對象。當XMLReader對象讀取到XML文件的開始和結束標簽時或者在取到一個節點內容時,都會觸發在Handler(事件處理器)中注冊的相應事件。

  在XMLReader中可以通過setContentHandler(ContentHandler handler)方法來調用我們自己的Handler,而這個Handler就是我們解析XML文件的核心。我們可以通過繼承SDK中的DefaultHandler類來實現一個我們自己的Handler。針對我們今天的主題,主要需要實現以下幾個方法。

  • public void startDocument() throws SAXException{}——讀取到文檔時觸發的事件,通常可以通過這個事件來處理一些IO錯誤之類的事情。
  • public void startElement(String uri, String localName, String qName,Attributes attributes) throws SAXException{}——讀取到XML文檔內容中的標簽時觸發,如<work></work>中的<work>標簽。
    • uri  XML文檔中NameSpace的URI,如果不清楚XML文檔中Namespace的可以去網上看看。
    • localName  無前綴的標簽名,如<works><work></work></works>標簽,返回的可以是work字符串。
    • qName  有前綴具有完整路徑的標簽名,如<works><work></work></works>中返回的是/works/work字符串。
    • attributes  標簽中的屬性名,如<work id=”111”></work>這里面的id就是屬性,而”111”就是屬性值。
  • public void endElement(String uri, String localName, String qName)throws SAXException{}——讀取到XML文檔內容中的結束標簽時觸發。
  • public void endDocument() throws SAXException{}——讀取到XML文檔結尾時觸發該事件。
  • public void characters(char[] ch, int start, int length)throws SAXException{}——讀取到XML文檔某個標簽下的內容時,就會調用這個方法返回該內容。
    • ch  內容的字符值。
    • start   讀取的開始位置。
    • length  讀取的內容長度。

  a) 現在來理下要解析XML文檔的整個思路

    • 新建一個SAXParserFactory對象,通過該對象的newSAXParser()方法來獲得一個SAXParser對象。
    • 通過SAXParser對象的getXMLReader()方法來獲得一個XMLReader對象。
    • 利用XMLReader對象的setConentHandler()方法來注冊一個我們自己的Handler對象。
    • 利用XMLReader對象的parse()方法來開始處理我們的XML文檔。
    • 實現自己的Handler類。

  b) 普通方式下的解析

 1 package LiB.XMLDemo;
2
3 import org.xml.sax.Attributes;
4 import org.xml.sax.SAXException;
5 import org.xml.sax.helpers.DefaultHandler;
6
7 public class SAXHandler extends DefaultHandler {
8
9 String tagName;
10 //當有值存在時,就調用該方法解析取值(如果是空值,也會調用這個方法)
11 @Override
12 public void characters(char[] ch, int start, int length)
13 throws SAXException {
14 String value= new String(ch, start,length);
15 if(tagName.equals("name"))
16 {
17 System.out.println("name="+ value);
18 }
19 if(tagName.equals("age"))
20 {
21 System.out.println("age="+value);
22 }
23 }
24   
25 @Override
26 public void endDocument() throws SAXException {
27
28 System.out.println("---end----");
29 }
30
31 @Override
32 public void endElement(String uri, String localName, String qName)
33 throws SAXException {
34 if(localName.equals("work"))
35 {
36 System.out.println("-----end----work");
37 }
38 }
39
40 @Override
41 public void startDocument() throws SAXException {
42
43 System.out.println("---begin----");
44 }
45
46 @Override
47 public void startElement(String uri, String localName, String qName,
48 Attributes attributes) throws SAXException {
49 tagName = localName;
50 if(localName.equals("work"))
51 {
52 for(int i=0;i< attributes.getLength();i++)
53 {
54 System.out.println(attributes.getLocalName(i)+"="+attributes.getValue(i));
55 }
56 }
57 }
58
59 }


  上面這個方法中存在一個問題:在讀取出來的數據中,沒區分開始標簽和結束標簽,所以出現了空值的狀況。這個問題我一直都很奇怪,因為在不久前我處理的時候是不存在這個問題的,可是現在出現了。

  c) 改進后的解析

  解決的方法在網上也挺多的,而且大家都比較相似,就是在startElement和endElement方法中設置相應的標志位,然后在characters方法中通過標志位來決定是否需要讀取它的內容。

  修改后的方法有興趣的朋友可以把源碼下載下來看看。

2、 DOM解析

  DOM方式解析XML文件呢,就需要將整個XML文檔裝入我們的手機內存中,如果文檔過大,那么將非常的耗費內存,但是這樣的好處是解析速度很快,同時DOM解析方式可以只解析你需要的那個部分,靈活性非常大。

  DOM解析的原理呢,其實就是把動過DOM API訪問XML文檔的樹形結構,並獲取相應的數據。在java中通過DOM解析XML文件,一般會涉及到以下幾個類。

  • DocumentBuilderFactory——創建DocumentBuilder對象的工廠類。
  • DocumentBuilder——通過這個方法可以創建一個能夠獲取Document實例的API。
  • Document——加載XML文檔的入口,這是解析文檔的源所在。
  • Element——元素,在DOM中,所有的節點都可以稱作Element。
  • NodeList——節點的集合。

  來看看通過DOM方式解析XML文檔的步驟吧:

  • 通過javax.xml.parsers包中的DocumentBuilderFactory類的newInstance()方法新建一個DocumentBuilderFactory對象。
  • 通過DocumentBuilderFactory對象的newDocumentBuilder ()方法創建一個DoucumentBuilder對象。
  • 通過DoucumentBuilder的parse()方法讀取外部流來創建一個Document對象。
  • 通過Document對象來獲得文檔中的所有節點的根節點。
  • 通過根節點來解析所需要的文件內容。
 1 package LiB.XMLDemo;
2
3
4 import javax.xml.parsers.DocumentBuilder;
5 import javax.xml.parsers.DocumentBuilderFactory;
6
7 import org.w3c.dom.Document;
8 import org.w3c.dom.Element;
9 import org.w3c.dom.Node;
10 import org.w3c.dom.NodeList;
11 import org.xml.sax.InputSource;
12
13 public class DomHandler {
14 public static void GetStringFromDom(InputSource inputSource) {
15 try {
16 DocumentBuilderFactory factory = DocumentBuilderFactory
17 .newInstance();
18 DocumentBuilder builder = factory.newDocumentBuilder();
19 Document document = builder.parse(inputSource);
20 //獲取根節點
21 Element rootElement = document.getDocumentElement();
22 //獲取第一級子節點
23 NodeList nodeList = rootElement.getElementsByTagName("work");
24 for(int i=0 ; i<nodeList.getLength();i++)
25 {
26 //String work = rootElement.getElementsByTagName("name").item(0).getFirstChild().getNodeValue();
27
28 Element workElement = ((Element)nodeList.item(i));
29 //獲取節點中的屬性值
30 //String attr= workElement.getAttribute("XXX");
31 //通過節點的標簽名字來獲取值
32 String name = workElement.getElementsByTagName("name").item(0).getFirstChild().getNodeValue();
33 String age = workElement.getElementsByTagName("age").item(0).getFirstChild().getNodeValue();
34 System.out.println("name="+name);
35 System.out.println("age="+age);
36 }
37
38 } catch (Exception e) {
39 }
40 }
41 }

  其實是用DOM方式來解析XML文件,有一些.NET和java開發經驗的同學看到上面的代碼都應該非常親切,因為這和在.NET和java中相似。

3、 二者區別

  SAX——流式解析,通過事件模型解析XML文件,對內存消耗比較小。但是只能順序解析,也就是說如果你需要的數據在文件的末尾,那么你將需要把整個XML文件全部解析才能得到你想要的數據。

  Dom解析——符合W3C標准的一種解析方式。解析速度非常快。在幾乎所有的語言中,都能使用,可以解析你所需要的數據(不管這個數據在文件中間還是文件末尾)。但是這個需要全部加載進系統內存中才能進行解析。

 三、總結

  這這個筆記中介紹了兩種解析XML文檔的方法。從下篇筆記開始,我將介紹如何與藍牙、WIFI、網絡傳輸相關的一些知識。

【源碼下載】


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM