學習過程
安卓中有三種對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檔案中的位置是這樣)
簡單總結就是:- 文檔的開頭和結束分别有文檔開始和文檔結束事件
- 文檔中的每個節點,無論是根節點還是葉子節點,都在節點開始和節點結束的地方有事件
具體使用的建議:
- 文檔開始和文檔結束事件是有固定位置的,你隻要在這個位置做你要做的事情就好了,比如初始化一些資源
- 節點開始和節點結束的事件在很多位置都可能發生,為了精确控制,你可以使用【擷取他們的節點名稱(name)進行判斷】這一方法
三種解析方式對比
JAVA 解析 XML 通常有兩種方式:DOM 和SAX(PULL)
- DOM
- DOM是結構化解析,會在記憶體中維護一個完整的XML的樹狀結構,開銷大,對某些複雜需求可能比較友善
- XML DOM 是 XML Document Object Model 的縮寫,即 XML 文檔對象模型。DOM(文檔對象模型)是W3C标準,提供了标準的解析方式,但其解析效率一直不盡如人意,這是因為DOM解析XML文檔時,把所有内容一次性的裝載入記憶體,并建構一個駐留在記憶體中的樹狀結構(節點數)。如果需要解析的XML文檔過大,或者我們隻對該文檔中的一部分感興趣,這樣就會引起性能問題。
- 它有一個非常龐大的事件庫
- SAX(PULL)
- SAX和PULL的原理是一樣的,都不維護什麼完整的結構,而是逐行掃描,不儲存結構關系,開銷小,适合簡單的需求
- (兩者差別是,SAX使用回調的方式實作,PULL使用switch case的方式實作)
- 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