Android 使用Pull方法解析XML文件的方法
org.xmlpull.v1.XmlPullParser;
org.xmlpull.v1.XmlPullParserFactory;
二個(gè)類,其中主要使用的是XmlPullParser,XmlPullParserFactory是一個(gè)工廠,用于構(gòu)建XmlPullParser對(duì)象。
應(yīng)用程序通過(guò)調(diào)用XmlPullParser.next()等方法來(lái)產(chǎn)生Event,然后再處理Event??梢钥吹剿cPush方法的不同,Push方法是由Parser自己主動(dòng)產(chǎn)生Event,回調(diào)給應(yīng)用程序。而Pull方法是主動(dòng)的調(diào)用Parser的方法才能產(chǎn)生事件。
假如XML中的語(yǔ)句是這樣的:"<author country="United States">James Elliott</author>",author是TAG,country是ATTRIBUTE,"James Elliott"是TEXT。
要想解析文檔先要構(gòu)建一個(gè)XmlPullParser對(duì)象
final XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(true);
final XmlPullParser parser = factory.newPullParser();
Pull解析是一個(gè)遍歷文檔的過(guò)程,每次調(diào)用next(),nextTag(), nextToken()和nextText()都會(huì)向前推進(jìn)文檔,并使Parser停留在某些事件上面,但是不能倒退。
然后把文檔設(shè)置給Parser
parser.setInput(new StringReader("<author country=\"United States\">James Elliott</author>");
這時(shí),文檔剛被初始化,所以它應(yīng)該位于文檔的開(kāi)始,事件應(yīng)該是START_DOCUMENT,可以通過(guò)XmlPullParser.getEventType()來(lái)獲取。然后調(diào)用next()會(huì)產(chǎn)生
START_TAG,這個(gè)事件告訴應(yīng)用程序一個(gè)標(biāo)簽已經(jīng)開(kāi)始了,調(diào)用getName()會(huì)返回"author";再next()會(huì)產(chǎn)生
TEXT事件,調(diào)用getText()會(huì)返回"James Elliott",再next(),會(huì)產(chǎn)生
END_TAG,這個(gè)告訴你一個(gè)標(biāo)簽已經(jīng)處理完了,再next(),會(huì)產(chǎn)生
END_DOCUMENT,它告訴你整個(gè)文檔已經(jīng)處理完成了。
除了next()外,nextToken()也可以使用,只不過(guò)它會(huì)返回更加詳細(xì)的事件,比如 COMMENT, CDSECT, DOCDECL, ENTITY等等非常詳細(xì)的信息。如果程序得到比較底層的信息,可以用nextToken()來(lái)驅(qū)動(dòng)并處理詳細(xì)的事件。需要注意一點(diǎn)的是TEXT事件是有可能返回空白的White Spaces比如換行符或空格等。
另外有二個(gè)非常實(shí)用的方法nextTag()和nextText()
nextTag()--首先它會(huì)忽略White Spaces,如果可以確定下一個(gè)是START_TAG或END_TAG,就可以調(diào)用nextTag()直接跳過(guò)去。通常它有二個(gè)用處:當(dāng)START_TAG時(shí),如果能確定這個(gè)TAG含有子TAG,那么就可以調(diào)用nextTag()產(chǎn)生子標(biāo)簽的START_TAG事件;當(dāng)END_TAG時(shí),如果確定不是文檔結(jié)尾,就可以調(diào)用nextTag()產(chǎn)生下一個(gè)標(biāo)簽的START_TAG。在這二種情況下如果用next()會(huì)有TEXT事件,但返回的是換行符或空白符。
nextText()--它只能在START_TAG時(shí)調(diào)用。當(dāng)下一個(gè)元素是TEXT時(shí),TEXT的內(nèi)容會(huì)返回;當(dāng)下一個(gè)元素是END_TAG時(shí),也就是說(shuō)這個(gè)標(biāo)簽的內(nèi)容為空,那么空字串返回;這個(gè)方法返回后,Parser會(huì)停在END_TAG上。比如:
<author>James Elliott</author>
<author></author>
<author/>
當(dāng)START_TAG時(shí),調(diào)用nextText(),依次返回:
"James Elliott"
""(empty)
""(empty)
這個(gè)方法在處理沒(méi)有子標(biāo)簽的標(biāo)簽時(shí)很有用。比如:
<title>What Is Hibernate</title>
<author>James Elliott</author>
<category>Web</category>
就可以用以下代碼來(lái)處理:
while (eventType != XmlPullParser.END_TAG) {
switch (eventType) {
case XmlPullParser.START_TAG:
tag = parser.getName();
final String content = parser.nextText();
Log.e(TAG, tag + ": [" + content + "]");
eventType = parser.nextTag();
break;
default:
break;
}
}
這就要比用next()來(lái)處理方便多了,可讀性也大大的加強(qiáng)了。
最后附上一個(gè)解析XML的實(shí)例Android程序
import java.io.IOException;
import java.io.InputStream;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
import android.util.Log;
public class RssPullParser extends RssParser {
private final String TAG = FeedSettings.GLOBAL_TAG;
private InputStream mInputStream;
public RssPullParser(InputStream is) {
mInputStream = is;
}
public void parse() throws ReaderBaseException, XmlPullParserException, IOException {
if (mInputStream == null) {
throw new ReaderBaseException("no input source, did you initialize this class correctly?");
}
final XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(true);
final XmlPullParser parser = factory.newPullParser();
parser.setInput(mInputStream);
int eventType = parser.getEventType();
if (eventType != XmlPullParser.START_DOCUMENT) {
throw new ReaderBaseException("Not starting with 'start_document'");
}
eventType = parseRss(parser);
if (eventType != XmlPullParser.END_DOCUMENT) {
throw new ReaderBaseException("not ending with 'end_document', do you finish parsing?");
}
if (mInputStream != null) {
mInputStream.close();
} else {
Log.e(TAG, "inputstream is null, XmlPullParser closed it??");
}
}
/**
* Parsing the Xml document. Current type must be Start_Document.
* After calling this, Parser is positioned at END_DOCUMENT.
* @param parser
* @return event end_document
* @throws XmlPullParserException
* @throws ReaderBaseException
* @throws IOException
*/
private int parseRss(XmlPullParser parser) throws XmlPullParserException, ReaderBaseException, IOException {
int eventType = parser.getEventType();
if (eventType != XmlPullParser.START_DOCUMENT) {
throw new ReaderBaseException("not starting with 'start_document', is this a new document?");
}
Log.e(TAG, "starting document, are you aware of that!");
eventType = parser.next();
while (eventType != XmlPullParser.END_DOCUMENT) {
switch (eventType) {
case XmlPullParser.START_TAG: {
Log.e(TAG, "start tag: '" + parser.getName() + "'");
final String tagName = parser.getName();
if (tagName.equals(RssFeed.TAG_RSS)) {
Log.e(TAG, "starting an RSS feed <<");
final int attrSize = parser.getAttributeCount();
for (int i = 0; i < attrSize; i++) {
Log.e(TAG, "attr '" + parser.getAttributeName(i) + "=" + parser.getAttributeValue(i) + "'");
}
} else if (tagName.equals(RssFeed.TAG_CHANNEL)) {
Log.e(TAG, "\tstarting an Channel <<");
parseChannel(parser);
}
break;
}
case XmlPullParser.END_TAG: {
Log.e(TAG, "end tag: '" + parser.getName() + "'");
final String tagName = parser.getName();
if (tagName.equals(RssFeed.TAG_RSS)) {
Log.e(TAG, ">> edning an RSS feed");
} else if (tagName.equals(RssFeed.TAG_CHANNEL)) {
Log.e(TAG, "\t>> ending an Channel");
}
break;
}
default:
break;
}
eventType = parser.next();
}
Log.e(TAG, "end of document, it is over");
return parser.getEventType();
}
/**
* Parse a channel. MUST be start tag of an channel, otherwise exception thrown.
* Param XmlPullParser
* After calling this function, parser is positioned at END_TAG of Channel.
* return end tag of a channel
* @throws XmlPullParserException
* @throws ReaderBaseException
* @throws IOException
*/
private int parseChannel(XmlPullParser parser) throws XmlPullParserException, ReaderBaseException, IOException {
int eventType = parser.getEventType();
String tagName = parser.getName();
if (eventType != XmlPullParser.START_TAG || !RssFeed.TAG_CHANNEL.equals(tagName)) {
throw new ReaderBaseException("not start with 'start tag', is this a start of a channel?");
}
Log.e(TAG, "\tstarting " + tagName);
eventType = parser.nextTag();
while (eventType != XmlPullParser.END_TAG) {
switch (eventType) {
case XmlPullParser.START_TAG: {
final String tag = parser.getName();
if (tag.equals(RssFeed.TAG_IMAGE)) {
parseImage(parser);
} else if (tag.equals(RssFeed.TAG_ITEM)) {
parseItem(parser);
} else {
final String content = parser.nextText();
Log.e(TAG, tag + ": [" + content + "]");
}
// now it SHOULD be at END_TAG, ensure it
if (parser.getEventType() != XmlPullParser.END_TAG) {
throw new ReaderBaseException("not ending with 'end tag', did you finish parsing sub item?");
}
eventType = parser.nextTag();
break;
}
default:
break;
}
}
Log.e(TAG, "\tending " + parser.getName());
return parser.getEventType();
}
/**
* Parse image in a channel.
* Precondition: position must be at START_TAG and tag MUST be 'image'
* Postcondition: position is END_TAG of '/image'
* @throws IOException
* @throws XmlPullParserException
* @throws ReaderBaseException
*/
private int parseImage(XmlPullParser parser) throws XmlPullParserException, IOException, ReaderBaseException {
int eventType = parser.getEventType();
String tag = parser.getName();
if (eventType != XmlPullParser.START_TAG || !RssFeed.TAG_IMAGE.equals(tag)) {
throw new ReaderBaseException("not start with 'start tag', is this a start of an image?");
}
Log.e(TAG, "\t\tstarting image " + tag);
eventType = parser.nextTag();
while (eventType != XmlPullParser.END_TAG) {
switch (eventType) {
case XmlPullParser.START_TAG:
tag = parser.getName();
Log.e(TAG, tag + ": [" + parser.nextText() + "]");
// now it SHOULD be at END_TAG, ensure it
if (parser.getEventType() != XmlPullParser.END_TAG) {
throw new ReaderBaseException("not ending with 'end tag', did you finish parsing sub item?");
}
eventType = parser.nextTag();
break;
default:
break;
}
}
Log.e(TAG, "\t\tending image " + parser.getName());
return parser.getEventType();
}
/**
* Parse an item in a channel.
* Precondition: position must be at START_TAG and tag MUST be 'item'
* Postcondition: position is END_TAG of '/item'
* @throws IOException
* @throws XmlPullParserException
* @throws ReaderBaseException
*/
private int parseItem(XmlPullParser parser) throws XmlPullParserException, IOException, ReaderBaseException {
int eventType = parser.getEventType();
String tag = parser.getName();
if (eventType != XmlPullParser.START_TAG || !RssFeed.TAG_ITEM.equals(tag)) {
throw new ReaderBaseException("not start with 'start tag', is this a start of an item?");
}
Log.e(TAG, "\t\tstarting " + tag);
eventType = parser.nextTag();
while (eventType != XmlPullParser.END_TAG) {
switch (eventType) {
case XmlPullParser.START_TAG:
tag = parser.getName();
final String content = parser.nextText();
Log.e(TAG, tag + ": [" + content + "]");
// now it SHOULD be at END_TAG, ensure it
if (parser.getEventType() != XmlPullParser.END_TAG) {
throw new ReaderBaseException("not ending with 'end tag', did you finish parsing sub item?");
}
eventType = parser.nextTag();
break;
default:
break;
}
}
Log.e(TAG, "\t\tending " + parser.getName());
return parser.getEventType();
}
}
- Android中使用sax解析xml文件的方法
- Android 解析XML 文件的四種方法總結(jié)
- Android中使用PULL方式解析XML文件深入介紹
- Android開(kāi)發(fā)之XML文件解析的使用
- android編程之XML文件解析方法詳解(附源碼)
- Android中使用pull解析器操作xml文件的解決辦法
- Android使用Pull解析器解析xml文件的實(shí)現(xiàn)代碼
- android開(kāi)發(fā)基礎(chǔ)教程—三種方式實(shí)現(xiàn)xml文件解析
- Android開(kāi)發(fā)之DOM解析xml文件的方法
- Android中對(duì)xml文件解析的3種方式總結(jié)
相關(guān)文章
android實(shí)現(xiàn)http中請(qǐng)求訪問(wèn)添加cookie的方法
這篇文章主要介紹了android實(shí)現(xiàn)http中請(qǐng)求訪問(wèn)添加cookie的方法,實(shí)例分析了兩種添加cookie的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-10-10Android WebView如何判定網(wǎng)頁(yè)加載的錯(cuò)誤
這篇文章主要介紹了Android WebView如何判定網(wǎng)頁(yè)加載的錯(cuò)誤,幫助大家更好的理解和學(xué)習(xí)使用Android,感興趣的朋友可以了解下2021-04-04Android Studio升級(jí)到3.0 Terminal 中文顯示異常解決
本篇文章主要介紹了Android Studio升級(jí)到3.0 Terminal 中文顯示異常解決,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2017-10-10android視頻截屏&手機(jī)錄屏實(shí)現(xiàn)代碼
本篇文章主要介紹了android視頻截屏&手機(jī)錄屏實(shí)現(xiàn)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-07-07android開(kāi)發(fā)教程之switch控件使用示例
這篇文章主要介紹了android開(kāi)的switch控件使用示例,需要的朋友可以參考下2014-04-04Android日期選擇器對(duì)話框DatePickerDialog使用詳解
這篇文章主要為大家詳細(xì)介紹了Android日期選擇器對(duì)話框DatePickerDialog的使用,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-01-01Android studio實(shí)現(xiàn)滑動(dòng)開(kāi)關(guān)
這篇文章主要為大家詳細(xì)介紹了Android studio實(shí)現(xiàn)滑動(dòng)開(kāi)關(guān),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-03-03Android開(kāi)發(fā)之Service用法實(shí)例
這篇文章主要介紹了Android開(kāi)發(fā)之Service用法,實(shí)例分析了Android中Service的功能及使用技巧,需要的朋友可以參考下2015-05-05Android主項(xiàng)目與Module中R類的區(qū)別詳解
這篇文章主要給大家介紹了關(guān)于Android主項(xiàng)目與Module中R類的區(qū)別的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)各位Android開(kāi)發(fā)者們具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2018-02-02