Android 系列學習之XML文本數據解析
什麼是XML? XML是一種擴展標誌語言。標準通用標記語言的子類,一種標記電子文件使其具有結構性的標記語言,一種可以有用戶自定義標誌的的源語言。
XMl的特點:
- 一種標記語言,很類似HTML
- 其宗旨是傳輸數據
- 標籤沒有被預定義,用戶需要自己定義標籤
- 具有較好的自我秒描述性
- 是W3C推薦標準
- 純文本信息
- 空格會被保留
XML與HTML有啥區別呢?
- XML旨在傳輸信息。XML被設置爲傳輸和儲存數據,焦點在數據內容;
- HTML旨在顯示信息。HTML被設計問顯示信息,焦點在信息的展示外觀;
- XML的標籤都沒有預定義,需要用戶自定義標籤,HTML則是所有表親都是預定義的。
常使用來解析XML數據的兩種方式:SAX解析,在Android中較爲流行的一種解析器;還有就是Document解析,在Android中,用的還是相對比較少的。
下面實例來比較一下兩種的區別。
Document 解析:
步聚
- 獲取document的解析工廠;DocumentBuilderFactory
- 獲取DocumentBuilderFactory
- 獲取Document實例
實例代碼:
//獲取Documen的解析工廠
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = documentBuilderFactory.newDocumentBuilder();
//獲取解析的器的對象Document
// inputStream爲讀取本地XML文件獲取到的inputStream或者是web獲取的inputStream,
// 這裏使用的是獲取web服務器上的XML文件的inputStream
Document document = builder.parse(inputStream);
這樣就可以輕鬆獲取到Document的實例了,下面看一下解析XML數據,其實也是挺簡單的。解析的數據文本是:
根據上述XML文本,解析數據
//獲取XML文件的“根”元素包括的內容,即最外從元素包含的內容
Element documentElement = document.getDocumentElement();
//獲取子對象的全部內容,返回一個包含全部子對象的隊列
NodeList nodeList = documentElement.getElementsByTagName("user");
for (int i = 0; i < nodeList.getLength(); i++) {
//獲取到nodeList的每一個子對象
Element node = (Element) nodeList.item(i);
//獲取該對象node的屬性 即數據的id
String id = node.getAttribute("id");
//再獲取node下的子元素 隊列
NodeList nameList = node.getElementsByTagName("name");
NodeList sexList = node.getElementsByTagName("sex");
NodeList classesList = node.getElementsByTagName("classes");
//提取數據
String name = nameList.item(0).getTextContent();
String sex = sexList.item(0).getTextContent();
String classes = classesList.item(0).getTextContent();
Log.e("nodeAttribute", id);
Log.e("name",name);
Log.e("sex",sex);
Log.e("classes",classes);
}
解析的結果:
結果是結束正確的。
下面看一下SAX解析XML文本數據。
SAX解析XML文檔採用事件驅動模式。什麼是事件驅動模式?它將XML文檔轉換成一系列的事件,由單獨的事件處理器來決定如何處理。
基於事件驅動的處理模式主要是基於事件源和事件處理器(或者叫監聽器)來工作的。一個可以產生事件的對象叫做事件源,而一個可以針對事件做出響應的對象就被叫做事件處理器。
步聚:
- 創建DefaultHandler子類並實現一定相應的方法
- 創建解析器的工廠類SAXParserFactory
- 創建解析器的解析類SAXParser
- 獲取XMLReader的實例
- 創建DefaultHandler子類註冊到XMLReader當中
- 將從XML文件獲取到的inputStream丟給XMLReader開始解析
實例代碼:
//獲取解析器工廠類
SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
//獲取解析器的解析類
SAXParser saxParser = saxParserFactory.newSAXParser();
//獲取XMLReader實例
XMLReader xmlReader = saxParser.getXMLReader();
//XMLReader 與創建DefaultHandler子類關聯(DefaultHandler註冊到XMLReader)
xmlReader.setContentHandler(new XMLHandlers());
//開始解析,InputStream爲從本地讀取XML文件獲得的InputStream
// 或者是從web上獲取的InputStream
xmlReader.parse(new InputSource(inputStream));
解析開始了,怎麼來獲取數據呢?還是用上面的XML文本數據
解析數據至少需要在創建DefaultHandler子類中複寫以下三方法
/**
* 開始讀取元素
*
* @param uri
* @param localName 無前綴的標籤
* @param qName 有前綴的標籤
* @param attributes 屬性集合
* @throws SAXException
*/
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
super.startElement(uri, localName, qName, attributes);
Log.e("startElement", "startElement");
this.localName = localName;
if ("user".equals(localName)) {
for (int i = 0; i < attributes.getLength(); i++) {
Log.e("user_id", attributes.getValue("id"));
}
}
}
/**
* 讀取元素結束
*
* @param uri
* @param localName 無前綴 的標籤
* @param qName 有前綴的標籤
* @throws SAXException
*/
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
super.endElement(uri, localName, qName);
Log.e("endElement", "endElement");
}
/**
* 解析數據
*
* @param ch 字符數組
* @param start 開始位置
* @param length 字符數組的長度
* @throws SAXException
*/
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
super.characters(ch, start, length);
Log.e("characters", "characters");
if (localName.equals("name")) {
name = new String(ch, start, length);
Log.e("name", name);
} else if (localName.equals("sex")) {
sex = new String(ch, start, length);
Log.e("sex", sex);
} else if (localName.equals("classes")) {
classes = new String(ch, start, length);
Log.e("classes", classes);
}
}
析出來的數據,有點兒難看,但是仔細看也不難,而且還會發現一點兒奇怪的東西。
09-17 15:05:10.637 2535-2553/? E/startDocument﹕ startDocument
09-17 15:05:10.639 2535-2553/? E/startElement﹕ startElement
09-17 15:05:10.639 2535-2553/? E/characters﹕ characters
09-17 15:05:10.639 2535-2553/? E/characters﹕ characters
09-17 15:05:10.639 2535-2553/? E/startElement﹕ startElement
09-17 15:05:10.639 2535-2553/? E/user_id﹕ 1
09-17 15:05:10.639 2535-2553/? E/characters﹕ characters
09-17 15:05:10.639 2535-2553/? E/characters﹕ characters
09-17 15:05:10.639 2535-2553/? E/startElement﹕ startElement
09-17 15:05:10.639 2535-2553/? E/characters﹕ characters
09-17 15:05:10.639 2535-2553/? E/name﹕ gaosi
09-17 15:05:10.639 2535-2553/? E/endElement﹕ endElement
09-17 15:05:10.639 2535-2553/? E/characters﹕ characters
09-17 15:05:10.639 2535-2553/? E/name﹕ [ 09-17 15:05:10.639 2535: 2553 E/characters ]
characters
09-17 15:05:10.639 2535-2553/? E/name﹕ [ 09-17 15:05:10.639 2535: 2553 E/startElement ]
startElement
09-17 15:05:10.639 2535-2553/? E/characters﹕ characters
09-17 15:05:10.639 2535-2553/? E/sex﹕ 男
09-17 15:05:10.639 2535-2553/? E/endElement﹕ endElement
09-17 15:05:10.640 2535-2553/? E/characters﹕ characters
09-17 15:05:10.640 2535-2553/? E/sex﹕ [ 09-17 15:05:10.640 2535: 2553 E/characters ]
characters
09-17 15:05:10.640 2535-2553/? E/sex﹕ [ 09-17 15:05:10.640 2535: 2553 E/startElement ]
startElement
09-17 15:05:10.640 2535-2553/? E/characters﹕ characters
09-17 15:05:10.640 2535-2553/? E/classes﹕ 3
09-17 15:05:10.640 2535-2553/? E/endElement﹕ endElement
09-17 15:05:10.640 2535-2553/? E/characters﹕ characters
09-17 15:05:10.640 2535-2553/? E/classes﹕ [ 09-17 15:05:10.640 2535: 2553 E/characters ]
characters
09-17 15:05:10.640 2535-2553/? E/classes﹕ [ 09-17 15:05:10.640 2535: 2553 E/endElement ]
endElement
09-17 15:05:10.640 2535-2553/? E/characters﹕ characters
09-17 15:05:10.640 2535-2553/? E/classes﹕ [ 09-17 15:05:10.640 2535: 2553 E/characters ]
characters
09-17 15:05:10.640 2535-2553/? E/classes﹕ [ 09-17 15:05:10.640 2535: 2553 E/startElement ]
startElement
09-17 15:05:10.640 2535-2553/? E/user_id﹕ 2
09-17 15:05:10.640 2535-2553/? E/characters﹕ characters
09-17 15:05:10.640 2535-2553/? E/characters﹕ characters
09-17 15:05:10.640 2535-2553/? E/startElement﹕ startElement
09-17 15:05:10.640 2535-2553/? E/characters﹕ characters
09-17 15:05:10.640 2535-2553/? E/name﹕ 張
09-17 15:05:10.641 2535-2553/? E/endElement﹕ endElement
09-17 15:05:10.641 2535-2553/? E/characters﹕ characters
09-17 15:05:10.641 2535-2553/? E/name﹕ [ 09-17 15:05:10.641 2535: 2553 E/characters ]
characters
09-17 15:05:10.641 2535-2553/? E/name﹕ [ 09-17 15:05:10.641 2535: 2553 E/startElement ]
startElement
09-17 15:05:10.641 2535-2553/? E/characters﹕ characters
09-17 15:05:10.641 2535-2553/? E/sex﹕ 男
09-17 15:05:10.641 2535-2553/? E/endElement﹕ endElement
09-17 15:05:10.641 2535-2553/? E/characters﹕ characters
09-17 15:05:10.641 2535-2553/? E/sex﹕ [ 09-17 15:05:10.641 2535: 2553 E/characters ]
characters
09-17 15:05:10.641 2535-2553/? E/sex﹕ [ 09-17 15:05:10.642 2535: 2553 E/startElement ]
startElement
09-17 15:05:10.642 2535-2553/? E/characters﹕ characters
09-17 15:05:10.642 2535-2553/? E/classes﹕ 3
09-17 15:05:10.642 2535-2553/? E/endElement﹕ endElement
09-17 15:05:10.642 2535-2553/? E/characters﹕ characters
09-17 15:05:10.642 2535-2553/? E/classes﹕ [ 09-17 15:05:10.642 2535: 2553 E/characters ]
characters
09-17 15:05:10.642 2535-2553/? E/classes﹕ [ 09-17 15:05:10.642 2535: 2553 E/endElement ]
endElement
09-17 15:05:10.642 2535-2553/? E/characters﹕ characters
09-17 15:05:10.642 2535-2553/? E/classes﹕ [ 09-17 15:05:10.643 2535: 2553 E/characters ]
characters
09-17 15:05:10.643 2535-2553/? E/classes﹕ [ 09-17 15:05:10.643 2535: 2553 E/startElement ]
startElement
09-17 15:05:10.643 2535-2553/? E/user_id﹕ 3
09-17 15:05:10.643 2535-2553/? E/characters﹕ characters
09-17 15:05:10.643 2535-2553/? E/characters﹕ characters
09-17 15:05:10.643 2535-2553/? E/startElement﹕ startElement
09-17 15:05:10.643 2535-2553/? E/characters﹕ characters
09-17 15:05:10.643 2535-2553/? E/name﹕ 李四
09-17 15:05:10.643 2535-2553/? E/endElement﹕ endElement
09-17 15:05:10.643 2535-2553/? E/characters﹕ characters
09-17 15:05:10.643 2535-2553/? E/name﹕ [ 09-17 15:05:10.643 2535: 2553 E/characters ]
characters
09-17 15:05:10.643 2535-2553/? E/name﹕ [ 09-17 15:05:10.643 2535: 2553 E/startElement ]
startElement
09-17 15:05:10.643 2535-2553/? E/characters﹕ characters
09-17 15:05:10.643 2535-2553/? E/sex﹕ 男
09-17 15:05:10.643 2535-2553/? E/endElement﹕ endElement
09-17 15:05:10.643 2535-2553/? E/characters﹕ characters
09-17 15:05:10.643 2535-2553/? E/sex﹕ [ 09-17 15:05:10.643 2535: 2553 E/characters ]
characters
09-17 15:05:10.643 2535-2553/? E/sex﹕ [ 09-17 15:05:10.644 2535: 2553 E/startElement ]
startElement
09-17 15:05:10.644 2535-2553/? E/characters﹕ characters
09-17 15:05:10.644 2535-2553/? E/classes﹕ 2
09-17 15:05:10.644 2535-2553/? E/endElement﹕ endElement
09-17 15:05:10.644 2535-2553/? E/characters﹕ characters
09-17 15:05:10.644 2535-2553/? E/classes﹕ [ 09-17 15:05:10.644 2535: 2553 E/characters ]
characters
09-17 15:05:10.644 2535-2553/? E/classes﹕ [ 09-17 15:05:10.644 2535: 2553 E/endElement ]
endElement
09-17 15:05:10.644 2535-2553/? E/characters﹕ characters
09-17 15:05:10.644 2535-2553/? E/classes﹕ [ 09-17 15:05:10.644 2535: 2553 E/characters ]
characters
09-17 15:05:10.644 2535-2553/? E/classes﹕ [ 09-17 15:05:10.644 2535: 2553 E/startElement ]
startElement
09-17 15:05:10.644 2535-2553/? E/user_id﹕ 4
09-17 15:05:10.644 2535-2553/? E/characters﹕ characters
09-17 15:05:10.644 2535-2553/? E/characters﹕ characters
09-17 15:05:10.644 2535-2553/? E/startElement﹕ startElement
09-17 15:05:10.644 2535-2553/? E/characters﹕ characters
09-17 15:05:10.644 2535-2553/? E/name﹕ 王
09-17 15:05:10.644 2535-2553/? E/endElement﹕ endElement
09-17 15:05:10.644 2535-2553/? E/characters﹕ characters
09-17 15:05:10.644 2535-2553/? E/name﹕ [ 09-17 15:05:10.644 2535: 2553 E/characters ]
characters
09-17 15:05:10.644 2535-2553/? E/name﹕ [ 09-17 15:05:10.644 2535: 2553 E/startElement ]
startElement
09-17 15:05:10.644 2535-2553/? E/characters﹕ characters
09-17 15:05:10.644 2535-2553/? E/sex﹕ 女
09-17 15:05:10.644 2535-2553/? E/endElement﹕ endElement
09-17 15:05:10.644 2535-2553/? E/characters﹕ characters
09-17 15:05:10.645 2535-2553/? E/sex﹕ [ 09-17 15:05:10.645 2535: 2553 E/characters ]
characters
09-17 15:05:10.645 2535-2553/? E/sex﹕ [ 09-17 15:05:10.645 2535: 2553 E/startElement ]
startElement
09-17 15:05:10.645 2535-2553/? E/characters﹕ characters
09-17 15:05:10.645 2535-2553/? E/classes﹕ 2
09-17 15:05:10.645 2535-2553/? E/endElement﹕ endElement
09-17 15:05:10.645 2535-2553/? E/characters﹕ characters
09-17 15:05:10.645 2535-2553/? E/classes﹕ [ 09-17 15:05:10.645 2535: 2553 E/characters ]
characters
09-17 15:05:10.645 2535-2553/? E/classes﹕ [ 09-17 15:05:10.645 2535: 2553 E/endElement ]
endElement
09-17 15:05:10.645 2535-2553/? E/characters﹕ characters
09-17 15:05:10.645 2535-2553/? E/classes﹕[ 09-17 15:05:10.645 2535: 2553 E/characters ]
characters
09-17 15:05:10.645 2535-2553/? E/classes﹕ [ 09-17 15:05:10.645 2535: 2553 E/startElement ]
startElement
09-17 15:05:10.645 2535-2553/? E/user_id﹕ 5
09-17 15:05:10.645 2535-2553/? E/characters﹕ characters
09-17 15:05:10.645 2535-2553/? E/characters﹕ characters
09-17 15:05:10.645 2535-2553/? E/startElement﹕ startElement
09-17 15:05:10.645 2535-2553/? E/characters﹕ characters
09-17 15:05:10.645 2535-2553/? E/name﹕ 道
09-17 15:05:10.645 2535-2553/? E/endElement﹕ endElement
09-17 15:05:10.645 2535-2553/? E/characters﹕ characters
09-17 15:05:10.645 2535-2553/? E/name﹕ [ 09-17 15:05:10.645 2535: 2553 E/characters ]
characters
09-17 15:05:10.645 2535-2553/? E/name﹕ [ 09-17 15:05:10.645 2535: 2553 E/startElement ]
startElement
09-17 15:05:10.646 2535-2553/? E/characters﹕ characters
09-17 15:05:10.646 2535-2553/? E/sex﹕ 男
09-17 15:05:10.646 2535-2553/? E/endElement﹕ endElement
09-17 15:05:10.646 2535-2553/? E/characters﹕ characters
09-17 15:05:10.646 2535-2553/? E/sex﹕ [ 09-17 15:05:10.646 2535: 2553 E/characters ]
characters
09-17 15:05:10.646 2535-2553/? E/sex﹕ [ 09-17 15:05:10.646 2535: 2553 E/startElement ]
startElement
09-17 15:05:10.646 2535-2553/? E/characters﹕ characters
09-17 15:05:10.646 2535-2553/? E/classes﹕ 1
09-17 15:05:10.646 2535-2553/? E/endElement﹕ endElement
09-17 15:05:10.646 2535-2553/? E/characters﹕ characters
09-17 15:05:10.646 2535-2553/? E/classes﹕ [ 09-17 15:05:10.646 2535: 2553 E/characters ]
characters
09-17 15:05:10.646 2535-2553/? E/classes﹕ [ 09-17 15:05:10.646 2535: 2553 E/endElement ]
endElement
09-17 15:05:10.647 2535-2553/? E/characters﹕ characters
09-17 15:05:10.647 2535-2553/? E/classes﹕ [ 09-17 15:05:10.647 2535: 2553 E/characters ]
characters
09-17 15:05:10.647 2535-2553/? E/classes﹕ [ 09-17 15:05:10.648 2535: 2553 E/characters ]
characters
09-17 15:05:10.648 2535-2553/? E/classes﹕ [ 09-17 15:05:10.648 2535: 2553 E/characters ]
characters
09-17 15:05:10.648 2535-2553/? E/classes﹕ [ 09-17 15:05:10.649 2535: 2553 E/endElement ]
endElement
09-17 15:05:10.649 2535-2553/? E/endDocument﹕ endDocument
對比以下Document解析,你有沒有發現一點東西?
SAX 是逐行從上往下解析的,變掃描邊解析。而document解析則是將整個XML文本讀取掃描完畢,在從外往裏一層一層的解析。
聰明的人就會想到,這樣的話,我利用SAX解析,解析達到一定的條件,終止解析XML數據,這樣就會簡單很多了吧。對的。怎麼方法類中斷呢?
查看上面的解析結果,發現endDocument()是調用一次,可不可以到達特定的條件時候,調用該方法類終止解析呢?還有一種也可以使用return 來終止解析,是否可以呢?這兩個都是不行的。
不知道有沒有發現DefaultHandler子類的複寫方法都會拋異常, 我們只要在解析達到特定的條件時候,拋異常就OK了
在調用解析方法出捕獲一下異常
try{
//XMLReader 與創建DefaultHandler子類關聯(DefaultHandler註冊到XMLReader)
xmlReader.setContentHandler(new XMLHandlers());
//開始解析,InputStream爲從本地讀取XML文件獲得的InputStream
// 或者是從web上獲取的InputStream
xmlReader.parse(new InputSource(inputStream));
}catch (SAXException e){
//TODO去幹中斷解析的工作吧
//……
}
在characters()方法解析數據出等到達到特定條件就拋異常
if (localName.equals("name")) {
name = new String(ch, start, length);
Log.e("name", name);
if (name.equals("gaosi")){
super.endDocument();
throw new SAXException("中斷掃描,解析完成");
}
}
看一下區別:
總結:
在Android平臺中,SAX解析更符合用戶的而需求,不僅是簡單,耗能少,耗時也少,內存需求少等