天天看點

PULL解析學習

學習過程

安卓中有三種對XML解析的方式,這個衆所周知,DOM,SAX,PULL

其中被推薦的方法是PULL,說是非常簡單,但從一開始接觸就覺得比較迷惑,總是雲裡霧裡的感覺,甚至在自己寫出了一個能用的代碼, 我也解釋不了為什麼能用,也害怕去改,雖然有過幾次小小的突擊學習了解,但是沒有什麼進展

直到這次我花了點心思和時間準備搞一搞,才有了通關性進展

在開始研究并檢視一些資料的時候,當我看到一篇文章裡邊介紹了 5種解析事件的時候眼睛一亮,以為自己找到了了解的關鍵

但是在我繼續往下了解的時候,發現那種生疏的感覺一點沒少,感覺解析事件是關鍵,于是就繼續找關于它的更多資料

但是找了半天發現關于PULL解析事件的資料很少,另一方面我又了解到PULL是SAX的接替者,原理是差不多的,于是我又去找了SAX的解析事件相關的東西,可惜還是很少,然後之後不小心又找到DOM去了,DOM的事件類型龐大無比,看了一會感覺沒什麼用,就放棄了

直到最後看到一篇不錯的博文,然後又加上自己的分析,終于了解了問題的關鍵,就是:你得給我解釋,那五種解析事件在一個XML文檔中是在什麼地方啊,你光說有五種事件怎麼行。于是到最後我終于完全搞定了這塊,并且重構了我的解析工具代碼。

PULL解析了解

PULL是順序掃描XML的每一行,并且根據掃描到的事件來做出不同的行為

PULL一共有5種事件類型:

    * START_DOCUMENT:文檔的開始,解析器尚未讀取任何輸入。

    * START_TAG:開始标簽的解析。

    * TEXT:标簽内元素的内容解析。

    * END_TAG:結束标簽的解析。

    * END_DOCUMENT:文檔的結束。

主要用的是4個,他們與XML檔案相應内容是這麼對應的(他們在XML檔案中的位置是這樣)

PULL解析學習
簡單總結就是:

  1. 文檔的開頭和結束分别有文檔開始和文檔結束事件
  2. 文檔中的每個節點,無論是根節點還是葉子節點,都在節點開始和節點結束的地方有事件

具體使用的建議:

  1. 文檔開始和文檔結束事件是有固定位置的,你隻要在這個位置做你要做的事情就好了,比如初始化一些資源
  2. 節點開始和節點結束的事件在很多位置都可能發生,為了精确控制,你可以使用【擷取他們的節點名稱(name)進行判斷】這一方法

三種解析方式對比

JAVA 解析 XML 通常有兩種方式:DOM 和SAX(PULL)

  1. DOM
    1. DOM是結構化解析,會在記憶體中維護一個完整的XML的樹狀結構,開銷大,對某些複雜需求可能比較友善
    2. XML DOM 是 XML Document Object Model 的縮寫,即 XML 文檔對象模型。DOM(文檔對象模型)是W3C标準,提供了标準的解析方式,但其解析效率一直不盡如人意,這是因為DOM解析XML文檔時,把所有内容一次性的裝載入記憶體,并建構一個駐留在記憶體中的樹狀結構(節點數)。如果需要解析的XML文檔過大,或者我們隻對該文檔中的一部分感興趣,這樣就會引起性能問題。
    3. 它有一個非常龐大的事件庫
  2. SAX(PULL)
    1. SAX和PULL的原理是一樣的,都不維護什麼完整的結構,而是逐行掃描,不儲存結構關系,開銷小,适合簡單的需求
    2. (兩者差別是,SAX使用回調的方式實作,PULL使用switch case的方式實作)
    3. SAX是事件驅動型XML解析的一個标準接口,SAX的工作原理簡單地說就是對文檔進行順序掃描,當掃描到文檔(document)開始與結束、元素(element)開始與結束、文檔(document)結束等地方時通知事件處理函數,由事件處理函數做相應動作,然後繼續同樣的掃描,直至文檔結束。

示例代碼

上圖中XML的解析方法:

public static List<EleTimeValue> parseToETVL(String xmlData) {
        
        //在這建立變量,萬一try沒有的話,還能傳回null
        List<EleTimeValue> lists=null;  
        EleTimeValue eTV=null; 
        String value = "";
        String time ="";
        float valuef = 0;
        Date timed = null;
        
        SimpleDateFormat ft = new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss");
        
        try {
            
            XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
            XmlPullParser xmlPullParser = factory.newPullParser();
            xmlPullParser.setInput(new StringReader(xmlData));
            
            int eventType = xmlPullParser.getEventType();
            
            while (eventType != XmlPullParser.END_DOCUMENT) {
                
                String nodeName = xmlPullParser.getName();
                
                switch (eventType) {
                    
                //用eventType來控制什麼時候開始解析某個結點
                case XmlPullParser.START_DOCUMENT:  
                    lists=new ArrayList<EleTimeValue>();  
                    break; 
                
                //碰到STARTTAG之後開始一行行(eventtype可以當做行号)輸入下面的ifelse語句中進行判斷,不符合就跳出switch,并且在後邊把行号加1,然後繼續while循環
                case XmlPullParser.START_TAG: 
                    
                    //增加一個錯誤檢測,當解析内容時候發現errcode不為0的時候,直接結束解析,跳出swith,也跳出while,直接傳回null
                    //這裡傳不出msg
                    if ("ErrCode".equals(nodeName) && !xmlPullParser.nextText().equals("0") ){    
                        Log.d("t", "Null,要傳回");
                        return null;
                    }else if("RegValue".equals(nodeName)) {
                        eTV = new EleTimeValue();
                    }else if("Value".equals(nodeName)) {
                        value = xmlPullParser.nextText();
                        valuef = Float.valueOf(value).floatValue()/10;
                        eTV.setValue(valuef); 
                    }else if("DevTime".equals(nodeName)) {
                        time = xmlPullParser.nextText();
                        try { 
                            timed = ft.parse(time); 
                        } catch (ParseException e) {
                            System.out.println("Unparseable using " + ft); 
                        }
                        eTV.setDate(timed); 
                    } 
                    break;
                
                // 完成解析某個結點
                case XmlPullParser.END_TAG: 
                    if ("Reg".equals(nodeName)||"RegValue".equals(nodeName)) {
                        lists.add(eTV);
                        eTV = null;
                    }
                    break;

                }
                eventType = xmlPullParser.next();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        return lists;
    }      

參考文章:

http://baike.baidu.com/link?url=jyDUMCrvG56wJKcAxwDzBn6nuSy-m1yTxQCwNuT5N9Nu21crEkcibkg7DqOIZZGsDv4Mzi2gF48ak3EYAVVaMK