系列文章:
在Android開發之中,很重要的就是跟網路連線
今天談論XML的資料格式的傳遞
在Android的XML解析上有二種方式:
-
DOM (Document Object Model),他會把整份XML檔案載入,然後成為一個樹狀物件
-
SAX (Simple API for XML),照順序從頭向下讀,其中讀到一個節點、屬性…等,就採用事件的方式處理
很多效能測試上,SAX比DOM更有效率
這次的範例也是用SAX做的
這要配合XML格式來看
XML無所不在,最常用的RSS、你的Android的版面檔…
舉個RSS的例子好了,RSS也是用XML去做的
例如 Yahoo!奇摩 旅遊新聞
http://tw.news.yahoo.com/rss/travel
你用Chrome打開可能會長這樣
那是Chrome已經幫你整理過了,所有的元素(element)旁都有個箭頭可以縮放
這樣還是看不懂,沒關係,我來幫你整理一下
像一個旅遊新聞RSS大概長這樣
(以下內容有部份元素省略)
<?xml version=“1.0” encoding=“utf-8”?>
<rss version=“2.0” >
<channel>
<title>旅遊新聞 – 頭條新聞 – Yahoo!奇摩新聞</title>
<link>http://tw.news.yahoo.com/travel/</link>
<description>(…略)</description>
<language>zh-Hant-TW</language>
<pubDate>Sun, 06 Jan 2013 05:30:00 +0800</pubDate>
<ttl>5</ttl>
<item>
<title>冬日泡湯香港客愛北投</title>
<link>http://tw.news.yahoo.com/(…略)-024412185.html</link>
<pubDate>Sun, 06 Jan 2013 10:44:12 +0800</pubDate>
<description>(…略)</description>
</item>
</channel>
</rss>
就如從剛剛所提到,RSS是照著XML的格式規範走的
開頭第一行就有XML的宣告,之後的內容就跟HTML感覺很像啦
這文件包含了RSS的channel(頻道)、頻道的名字、連結、頻道介紹、語言別、更新日期…等
item裡面的東西比較重要,代表一個RSS項目(Maybe是一篇文章、新聞),它的標題、連結、時間、簡介…等
再看一個例子好了,例如小弟部落格的RSS
http://feed.pixnet.net/blog/posts/rss/j796160836
內容節錄在這:
<?xml version=“1.0” encoding=“UTF-8”?>
<rss xmlns:content=“http://purl.org/rss/1.0/modules/content/” xmlns:atom=“http://www.w3.org/2005/Atom” version=“2.0”>
<channel>
<title><![CDATA[清新下午茶 :: 痞客邦 PIXNET ::]]></title>
<link>http://j796160836.pixnet.net/blog</link>
<description><![CDATA[夏天的午後,來杯下午茶,分享你我的心。]]></description>
<pubDate>Thu, 15 Nov 2012 08:11:58 +0000</pubDate>
<copyright>Copyright 2003-2013 Johnny ,Pixnet Digital Media Coporation. All rights reserved.</copyright>
<generator>PIXNET Media Digital Coporation</generator>
<language>zh</language>
<docs>http://blogs.law.harvard.edu/tech/rss</docs>
<atom:link rel=“hub” href=“http://pubsubhubbub.appspot.com:80”/>
<item>
<title><![CDATA[[Android] 使用HTTP的POST方式和網頁表單溝通 (加上資料庫、執行緒)]]></title>
<link>http://j796160836.pixnet.net/blog/post/30577968</link>
<guid>http://j796160836.pixnet.net/blog/post/30577968</guid>
<description><![CDATA[ (…略) ]]></description>
<content:encoded><![CDATA[ (…略) ]]></content:encoded>
<pubDate>Thu, 05 Apr 2012 16:19:35 +0000</pubDate>
<category>Android</category>
<comments>http://j796160836.pixnet.net/blog/post/30577968#comments</comments>
</item>
</channel>
</rss>
雖然內容比較多,但很多只要看重點就可以了
從剛剛的例子知道
要找這個頻道的名稱要找
rss -> channel -> title
要找一個項目(文章)的標題,就
rss -> channel -> item -> title
(其實這只是方便理解,表示路徑有正規的寫法,叫XPath …有興趣可以google一下)
這裡多的xmlns:content、xmlns:atom、atom:link
都只是宣告不重要
但這裡多了個<content:encoded></content:encoded>標籤
它跟<description></description>的差別
只在於content:encoded是用HTML標籤格式化過的
而description是純文字
眼尖的你應該有發現<![CDATA[ ]]>符號
它是告訴剖析器(parser),用這符號括起來的內容,沒有做任何的跳脫處理
例如:< 符號要寫成 < 等等
請視為整段文字做處理
因為它是RSS,所以有格式規定
如果是你自己寫XML文件的話,格式都可以自己訂
剛剛提到了SAX採用事件的方式處理,所以我簡單列出以下的一些事件callback函數
文件類:
* XML文件開始解析時呼叫此method
public void startDocument() throws SAXException
* XML文件結束時呼叫此method
public void endDocument() throws SAXException
節點類:
* 解析到Element的開頭時呼叫此method
public void startElement(String namespaceURI, String localName,
String qName, Attributes atts) throws SAXException
* 解析到Element的結尾時呼叫此method
public void endElement(String namespaceURI, String localName, String qName)
throws SAXException
節點內容:
* 取得Element的開頭結尾中間夾的字串
public void characters(String fetchStr)
到時候配上程式碼就大致就會知道了
它到時候要接一個DefaultHandler實做以上方法
我的話通常會把RSS資料擺到自己設計的物件(Object)裡面
到時候直接存檔,用ArrayList配合ListView做資料展示都很方便
像在startDocument()的時候通常會做一些變數的宣告(ArrayList)
SAX的問題就是:我只知道讀到節點了,但我不知道讀到哪一個節點(多深)
很多書上都是寫用元素的名稱做判斷
但我提出一個更方便更精準的做法
我把讀取的歷程用Stack(堆疊)記錄下來
意指在 startElement() 時把qName給push進去
in_node.push(qName);
到了 endElement() 時把它pop掉
in_node.pop();
這個很簡單的動作我就可以知道我的歷程了
這篇先講概念,後面的程式碼才會看得比較有重點
參考資料
RSS的介紹
http://zh.wikipedia.org/zh-tw/RSS
http://tw.info.yahoo.com/rss/rookie.html
SAX的剖析方式
http://zh.wikipedia.org/zh-tw/SAX
CDDATA的說明
http://ianjung1974.blogspot.tw/2008/04/cdata-xml.html
Android 解析 XML
http://www.dotblogs.com.tw/nethawk/archive/2011/05/02/24047.aspx
嘿嘿嘿