在講這次錯誤之前,先看一下下面這段代碼。 【◆以下解析方法是錯誤的×】
- import java.util.ArrayList;
- import java.util.List;
-
- import org.xml.sax.Attributes;
- import org.xml.sax.SAXException;
- import org.xml.sax.helpers.DefaultHandler;
-
- import Android.util.Log;
-
- public class XmlHandler extends DefaultHandler{
-
- private final String TAG = this.getClass().getSimpleName();
-
- /**XML文件中標簽定義*/
- private final String TAG_Article = "Article";
- private final String TAG_ArticleID = "ArticleID";
- private final String TAG_Title = "Title";
- private final String TAG_Date = "Date";
- private final String TAG_SmallPictures = "SmallPictures";
- private final String TAG_LargePictures = "LargePictures";
- private final String TAG_Category = "Category";
- private static final String TAG_HeadNote = "HeadNote";
- private static final String TAG_SubTitle = "SubTitle";
- private static final String TAG_Source = "Source";
-
- //當前正在解析的TAG
- private String currentName;
-
- //單個文章
- private News news = null;
-
- //文章列表
- private List<News> newsList = null;
-
- //解析開始時間
- private long start_time;
-
- private boolean flag = false;
-
- @Override
- public void characters(char[] ch, int start, int length)
- throws SAXException {
- super.characters(ch, start, length);
-
- if(!flag) {
- return;
- }
- // 取值
- String value = new String(ch, start, length);
- Log.d(TAG, "Element: " + currentName + " Element Value: " + value);
- if(value != null) {
- if(TAG_ArticleID.equals(currentName)) {
- news.setArticleId(value);
- } else if(TAG_Title.equals(currentName)) {
- news.setTitle(value);
- } else if(TAG_Date.equals(currentName)) {
- news.setDate(value);
- } else if(TAG_Category.equals(currentName)) {
- news.setCategory(value);
- } else if(TAG_SmallPictures.equals(currentName)) {
- news.setSmallPicture(value);
- } else if(TAG_LargePictures.equals(currentName)) {
- news.setLargePicture(value);
- } else if(TAG_HeadNote.equals(currentName)) {
- news.setHeadNote(value);
- } else if(TAG_SubTitle.equals(currentName)) {
- news.setSubTitle(value);
- } else if(TAG_Source.equals(currentName)) {
- news.setSource(value);
- }
- }
- }
-
- @Override
- public void startDocument() throws SAXException {
- super.startDocument();
-
- start_time = System.currentTimeMillis();
- newsList = new ArrayList<News>();
- }
-
- @Override
- public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
- super.startElement(uri, localName, qName, attributes);
- this.currentName = localName;
- flag = true;
- if(TAG_Article.equals(localName)) {
- news = new News();
- }
- }
-
- @Override
- public void endElement(String uri, String localName, String qName)
- throws SAXException {
- super.endElement(uri, localName, qName);
- flag = false;
-
- if(TAG_Article.equals(localName)) {
- newsList.add(news);
- }
- }
-
- @Override
- public void endDocument() throws SAXException {
- super.endDocument();
-
- long end = System.currentTimeMillis();
- Log.d(TAG, "Parse List's Xml Cost: " + (end - start_time) + " !!");
- }
- }
Baidu 或者 Google 一下 “Android Sax 解析” , 給出的Sample無一例外都是如此。 坑爹啊... 甚至連有些書籍中都是這麼寫的, 比如《Android開發入門與實踐》 下載見 http://www.linuxidc.com/Linux/2011-11/48183.htm 。(本書親自確認過,其他書情況不詳)
沒錯, 一般情況下,這麼寫是可以的, 而且在大多數情況下解析出來也是正確的。 但是就是偶爾會出錯, 這個時候通常你都莫不著頭腦, 怎麼回事? 數據沒錯啊,解析部分代碼貌似也沒問題.. 真是奇了怪了。 其實問題都出在上面那段代碼上!!
大家都認為 SAX 解析過程大致如下:
startDocument -> startElement -> characters -> endElement -> endDocument
沒錯,就是這樣, startElement 讀取起始標簽, endElement 讀取結束標簽,characters 呢?當然是讀取其值, 這沒錯,但是大家都天真的以為 characters 只執行一次,並且一次就讀取了全部內容。錯就錯在這!
其實characters 是很有可能會執行多次的,當遇到內容中有回車,\t等等內容時,它很有可能就執行多次。 有的人可能會說,那我沒有這些是不是就只執行一次了? 看下我實測結果:
測試用XML如下:
- <News>
- <Article>
- <ArticleID>1000555</ArticleID>
- <Title><![CDATA[ 鄭州“亞洲第一橋”通車6年成危橋 ]]></Title>
- <Date>2011-11-25 14:23:52</Date>
- <SmallPictures>livenews/images/s20.png</SmallPictures>
- <LargePictures>livenews/images/l20.png</LargePictures>
- <Category>聞天下</Category>
- <HeadNote></HeadNote>
- <SubTitle></SubTitle>
- <Author></Author>
- <Source>人民日報</Source>
- <Abstract></Abstract>
- </Article>
- <Article>
- <ArticleID>1000554</ArticleID>
- <Title><![CDATA[ 內地事業單位擬設統一工資制度 ]]></Title>
- <Date>2011-11-25 14:22:33</Date>
- <Category><![CDATA[ 聞天下 ]]></Category>
- <HeadNote></HeadNote>
- <SubTitle></SubTitle>
- <Author></Author>
- <Source></Source>
- <Abstract></Abstract>
- </Article>
- <Article>
- <ArticleID>1000553</ArticleID>
- <Title></Title>
- <Date>2011-11-25 14:21:23</Date>
- <SmallPictures>livenews/images/s21.png</SmallPictures>
- <LargePictures>livenews/images/l21.png</LargePictures>
- <Category><![CDATA[ 星娛樂 ]]></Category>
- <HeadNote></HeadNote>
- <SubTitle></SubTitle>
- <Author></Author>
- <Source><![CDATA[ 鳳凰網綜合 ]]></Source>
- <Abstract></Abstract>
- </Article>
- <News>