1. 程式人生 > >android解析XML總結-SAX、Pull、Dom三種方式

android解析XML總結-SAX、Pull、Dom三種方式

     在android開發中,經常用到去解析xml檔案,常見的解析xml的方式有一下三種:SAX、Pull、Dom解析方式。最近做了一個android版的CSDN閱讀器,用到了其中的兩種(sax,pull),對android解析xml的這三種方式進行一次總結

channels.xml
<?xml version="1.0" encoding="utf-8"?>
<channel>
<item id="0" url="http://www.baidu.com">百度</item>
<item id="1" url="http://www.qq.com">騰訊</item>
<item id="2" url="http://www.sina.com.cn">新浪</item>
<item id="3" url="http://www.taobao.com">淘寶</item>
</channel>
 一、使用sax方式解析
 基礎知識:
     這種方式解析是一種基於事件驅動的api,有兩個部分,解析器和事件處理器,解析器就是XMLReader介面,負責讀取XML文件,和向事件處理器傳送事件(也是事件源),事件處理器ContentHandler介面,負責對傳送的事件響應和進行XML文件處理。
     下面是ContentHandler介面的常用方法
     public abstract void characters (char[] ch, int start, int length)
      這個方法來接收字元塊通知,解析器通過這個方法來報告字元資料塊,解析器為了提高解析效率把讀到的所有字串放到一個字元陣列(ch)中,作為引數傳遞給character的方法中,如果想獲取本次事件中讀取到的字元資料,需要使用start和length屬性。
    public abstract void startDocument () 接收文件開始的通知
    public abstract void endDocument () 接收文件結束的通知
    public abstract void startElement (String uri, String localName, String qName, Attributes atts) 接收文件開始的標籤
    public abstract void endElement (String uri, String localName, String qName) 接收文件結束的標籤
    在一般使用中為了簡化開發,在org.xml.sax.helpers提供了一個DefaultHandler類,它實現了ContentHandler的方法,我們只想繼承DefaultHandler方法即可。
   另外SAX解析器提供了一個工廠類:SAXParserFactory,SAX的解析類為SAXParser 可以呼叫它的parser方法進行解析。
 1 public class SAXPraserHelper extends DefaultHandler {
 3     final int ITEM = 0x0005;
 5     List<channel> list;
 6     channel chann;
 7     int currentState = 0;
 8 
 9     public List<channel> getList() {
10         return list;
11     }

     /*
      * 介面字元塊通知
      */
     @Override
17     public void characters(char[] ch, int start, int length)
18             throws SAXException {
20 // super.characters(ch, start, length);
21         String theString = String.valueOf(ch, start, length);
22         if (currentState != 0) {
23             chann.setName(theString);
24             currentState = 0;
25         }
26         return;
27     }
29     /*
30      * 接收文件結束通知
31      */
32     @Override
33     public void endDocument() throws SAXException {
35         super.endDocument();
36     }
38     /*
39      * 接收標籤結束通知
40      */
41     @Override
42     public void endElement(String uri, String localName, String qName)
43             throws SAXException {
45         if (localName.equals("item"))
46             list.add(chann);
47     }
49     // 文件開始通知
52     @Override
53     public void startDocument() throws SAXException {
55         list = new ArrayList<channel>();
56     }
57 
58     /*
59      * 標籤開始通知
60      */
61     @Override
62     public void startElement(String uri, String localName, String qName,
63             Attributes attributes) throws SAXException {
65         chann = new channel();
66         if (localName.equals("item")) {
67             for (int i = 0; i < attributes.getLength(); i++) {
68                 if (attributes.getLocalName(i).equals("id")) {
69                     chann.setId(attributes.getValue(i));
70                 } else if (attributes.getLocalName(i).equals("url")) {
71                     chann.setUrl(attributes.getValue(i));
72                 }
73             }
74             currentState = ITEM;
75             return;
76         }
77         currentState = 0;
78         return;
79     }
 }

 private List<channel> getChannelList() throws ParserConfigurationException, SAXException, IOException  {
 3         //例項化一個SAXParserFactory物件
 4         SAXParserFactory factory=SAXParserFactory.newInstance();
 5         SAXParser parser;
 6         //例項化SAXParser物件,建立XMLReader物件,解析器
 7         parser=factory.newSAXParser();
 8         XMLReader xmlReader=parser.getXMLReader();
 9         //例項化handler,事件處理器
10         SAXPraserHelper helperHandler=new SAXPraserHelper();
11         //解析器註冊事件
12         xmlReader.setContentHandler(helperHandler);
13         //讀取檔案流
14         InputStream stream=getResources().openRawResource(R.raw.channels);
15         InputSource is=new InputSource(stream);
16         //解析檔案
17         xmlReader.parse(is);
18         return helperHandler.getList();
   }
從第二部分程式碼,可以看出使用SAX解析XML的步驟:
1、例項化一個工廠SAXParserFactory
2、例項化SAXPraser物件,建立XMLReader 解析器
3、例項化handler,處理器
4、解析器註冊一個事件
5、讀取檔案流
6、解析檔案
二、使用pull方式解析
      在android系統中,很多資原始檔中,很多都是xml格式,在android系統中解析這些xml的方式,是使用pul解析器進行解析的,它和sax解析一樣(個人感覺要比sax簡單點),也是採用事件驅動進行解析的,當pull解析器,開始解析之後,我們可以呼叫它的next()方法,來獲取下一個解析事件(就是開始文件,結束文件,開始標籤,結束標籤),當處於某個元素時可以呼叫XmlPullParser的getAttributte()方法來獲取屬性的值,也可呼叫它的nextText()獲取本節點的值。
 1 private List<Map<String, String>> getData() {
 2         List<Map<String, String>> list = new ArrayList<Map<String, String>>();
 3         XmlResourceParser xrp = getResources().getXml(R.xml.channels);
 5         try {
 6             // 直到文件的結尾處
 7             while (xrp.getEventType() != XmlResourceParser.END_DOCUMENT) {
 8                 // 如果遇到了開始標籤
 9                 if (xrp.getEventType() == XmlResourceParser.START_TAG) {
10                     String tagName = xrp.getName();// 獲取標籤的名字
11                     if (tagName.equals("item")) {
12                         Map<String, String> map = new HashMap<String, String>();
13                         String id = xrp.getAttributeValue(null, "id");// 通過屬性名來獲取屬性值
14                         map.put("id", id);
15                         String url = xrp.getAttributeValue(1);// 通過屬性索引來獲取屬性值
16                         map.put("url", url);
17                         map.put("name", xrp.nextText());
18                         list.add(map);
19                     }
20                 }
21                 xrp.next();// 獲取解析下一個事件
22             }
23         } catch (XmlPullParserException e) {
25             e.printStackTrace();
26         } catch (IOException e) {
28             e.printStackTrace();
29         }
           return list;
       }
三、使用Dom方式解析
     最後來看看Dom解析方式,這種方式解析自己之前也沒有用過(在j2ee開發中比較常見,沒有做過這方面的東西),在Dom解析的過程中,是先把dom全部檔案讀入到記憶體中,然後使用dom的api遍歷所有資料,檢索想要的資料,這種方式顯然是一種比較消耗記憶體的方式,對於像手機這樣的移動裝置來講,記憶體是非常有限的,所以對於比較大的XML檔案,不推薦使用這種方式,但是Dom也有它的優點,它比較直觀,在一些方面比SAX方式比較簡單。在xml文件比較小的情況下也可以考慮使用dom方式。
Dom方式解析的核心程式碼如下:
 1 public static List<channel> getChannelList(InputStream stream) {
 3         List<channel> list=new ArrayList<channel>();      
 5         //得到 DocumentBuilderFactory 物件, 由該物件可以得到 DocumentBuilder 物件
 6         DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
 7         
 8         try {
 9             //得到DocumentBuilder物件
10             DocumentBuilder builder=factory.newDocumentBuilder();
11             //得到代表整個xml的Document物件
12             Document document=builder.parse(stream);
13             //得到 "根節點" 
14             Element root=document.getDocumentElement();
15             //獲取根節點的所有items的節點
16             NodeList items=root.getElementsByTagName("item");  
17             //遍歷所有節點
18             for(int i=0;i<items.getLength();i++)  {
20                 channel chann=new channel();
21                 Element item=(Element)items.item(i);
22                 chann.setId(item.getAttribute("id"));
23                 chann.setUrl(item.getAttribute("url"));
24                 chann.setName(item.getFirstChild().getNodeValue());
25                 list.add(chann);
26             }
28         } catch (ParserConfigurationException e) {
30             e.printStackTrace();
31         } catch (SAXException e) {
33             e.printStackTrace();
34         } catch (IOException e) {
36             e.printStackTrace();
37         } 
39         return list;
40     }
總結一下Dom解析的步驟(和sax類似)
1、呼叫 DocumentBuilderFactory.newInstance() 方法得到 DOM 解析器工廠類例項。
2、呼叫解析器工廠例項類的 newDocumentBuilder() 方法得到 DOM 解析器物件
3、呼叫 DOM 解析器物件的 parse() 方法解析 XML 文件得到代表整個文件的 Document 物件。
四、總結

       除以上三種外還有很多解析xml的方法,但其基本的解析方式包含兩種,一種是事件驅動的(代表SAX),另一種方式是基於文件結構(代表DOM)