編輯:Android開發實例
上一節中,我們使用DOM方式解析xml文檔,該方式比較符合我們日常思維方式,容易上手,但是它直接把文檔調入內存中,比較耗內存。在這裡我們可以用另外一種方式解析xml,這個就是SAX方式。
SAX即是:Simple API for XML
SAX是基於事件驅動的。當然android的事件機制是基於回調函數的,在用SAX解析xml文檔時候,在讀取到文檔開始和結束標簽時候就會回調一個事件,在讀取到其他節點與內容時候也會回調一個事件。
既然涉及到事件,就有事件源,事件處理器。在SAX接口中,事件源是org.xml.sax包中的XMLReader,它通過parser()方法來解析XML文檔,並產生事件。事件處理器是org.xml.sax包中ContentHander、DTDHander、ErrorHandler,以及EntityResolver這4個接口
XMLReader通過相應事件處理器注冊方法setXXXX()來完成的與ContentHander、DTDHander、ErrorHandler,以及EntityResolver這4個接口的連接,詳細介紹請見下表:
但是我們無需都繼承這4個接口,SDK為我們提供了DefaultHandler類來處理,DefaultHandler類的一些主要事件回調方法如下:
由以上可知,我們需要XmlReader 以及DefaultHandler來配合解析xml。
處理思路是:
1:創建SAXParserFactory對象
2: 根據SAXParserFactory.newSAXParser()方法返回一個SAXParser解析器
3:根據SAXParser解析器獲取事件源對象XMLReader
4:實例化一個DefaultHandler對象
5:連接事件源對象XMLReader到事件處理類DefaultHandler中
6:調用XMLReader的parse方法從輸入源中獲取到的xml數據
7:通過DefaultHandler返回我們需要的數據集合。
代碼如下:
public List<River> parse(String xmlPath){
List<River> rivers=null;
SAXParserFactory factory=SAXParserFactory.newInstance();
try {
SAXParser parser=factory.newSAXParser();
//獲取事件源
XMLReader xmlReader=parser.getXMLReader();
//設置處理器
RiverHandler handler=new RiverHandler();
xmlReader.setContentHandler(handler);
//解析xml文檔
//xmlReader.parse(new InputSource(new URL(xmlPath).openStream()));
xmlReader.parse(new InputSource(this.context.getAssets().open(xmlPath)));
rivers=handler.getRivers();
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return rivers;
}
重點在於DefaultHandler對象中對每一個元素節點,屬性,文本內容,文檔內容進行處理。
前面說過DefaultHandler是基於事件處理模型的,基本處理方式是:當SAX解析器導航到文檔開始標簽時回調startDocument方法,導航到文檔結束標簽時回調endDocument方法。當SAX解析器導航到元素開始標簽時回調startElement方法,導航到其文本內容時回調characters方法,導航到標簽結束時回調endElement方法。
根據以上的解釋,我們可以得出以下處理xml文檔邏輯:
1:當導航到文檔開始標簽時,在回調函數startDocument中,可以不做處理,當然你可以驗證下UTF-8等等。
2:當導航到rivers開始標簽時,在回調方法startElement中可以實例化一個集合用來存貯list,不過我們這裡不用,因為在構造函數中已經實例化了。
3:導航到river開始標簽時,就說明需要實例化River對象了,當然river標簽中還有name ,length屬性,因此實例化River後還必須取出屬性值,attributes.getValue(NAME),同時賦予river對象中,同時添加為導航到的river標簽添加一個boolean為真的標識,用來說明導航到了river元素。
4:當然有river標簽內還有子標簽(節點),但是SAX解析器是不知道導航到什麼標簽的,它只懂得開始,結束而已。那麼如何讓它認得我們的各個標簽呢?當然需要判斷了,於是可以使用回調方法startElement中的參數String localName,把我們的標簽字符串與這個參數比較下,就可以了。我們還必須讓SAX知道,現在導航到的是某個標簽,因此添加一個true屬性讓SAX解析器知道。因此
5:它還會導航到文本內標簽,(就是<img></img>裡面的內容),回調方法characters,我們一般在這個方法中取出就是<img></img>裡面的內容,並保存。
6:當然它是一定會導航到結束標簽</river> 或者</rivers>的,如果是</river>標簽,記得把river對象添加進list中。如果是river中的子標簽</introduction>,就把前面設置標記導航到這個標簽的boolean標記設置為false.
按照以上實現思路,可以實現如下代碼:
/**導航到開始標簽觸發**/
public void startElement (String uri, String localName, String qName, Attributes attributes){
String tagName=localName.length()!=0?localName:qName;
tagName=tagName.toLowerCase().trim();
//如果讀取的是river標簽開始,則實例化River
if(tagName.equals(RIVER)){
isRiver=true;
river=new River();
/**導航到river開始節點後**/
river.setName(attributes.getValue(NAME));
river.setLength(Integer.parseInt(attributes.getValue(LENGTH)));
}
//然後讀取其他節點
if(isRiver){
if(tagName.equals(INTRODUCTION)){
xintroduction=true;
}else if(tagName.equals(IMAGEURL)){
ximageurl=true;
}
}
}
/**導航到結束標簽觸發**/
public void endElement (String uri, String localName, String qName){
String tagName=localName.length()!=0?localName:qName;
tagName=tagName.toLowerCase().trim();
//如果讀取的是river標簽結束,則把River添加進集合中
if(tagName.equals(RIVER)){
isRiver=true;
rivers.add(river);
}
//然後讀取其他節點
if(isRiver){
if(tagName.equals(INTRODUCTION)){
xintroduction=false;
}else if(tagName.equals(IMAGEURL)){
ximageurl=false;
}
}
}
//這裡是讀取到節點內容時候回調
public void characters (char[] ch, int start, int length){
//設置屬性值
if(xintroduction){
//解決null問題
river.setIntroduction(river.getIntroduction()==null?"":river.getIntroduction()+new String(ch,start,length));
}else if(ximageurl){
//解決null問題
river.setImageurl(river.getImageurl()==null?"":river.getImageurl()+new String(ch,start,length));
}
}
運行結果如下:
Android提供了許多方法來控制播放的音頻/視頻文件和流。其中該方法是通過一類稱為MediaPlayer。Android是提供MediaPlayer類訪問內置的媒體播放
前言 本文主要介紹在Android中怎樣來解析XML文件。主要采用的是SAX機制,SAX全稱為Simple API for XML,它既是一種
本文介紹一個簡易的標准體重計算器Android應用的開發實例。此功能在以前的手
Android應用程序可以在許多不同地區的許多設備上運行。為了使應用程序更具交互性,應用程序應該處理以適合應用程序將要使用的語言環境方面的文字,數字,文件等。在本章中,我