Parsing XML Data

Extensible Markup Language (XML) is a set of rules for encoding documents in machine-readable form. XML is a popular format for sharing data on the internet. Websites that frequently update their content, such as news sites or blogs, often provide an XML feed so that external programs can keep abreast of content changes. Uploading and parsing XML data is a common task for network-connected apps. This lesson explains how to parse XML documents and use their data.

Choose a Parser


We recommend XmlPullParser, which is an efficient and maintainable way to parse XML on Android. Historically Android has had two implementations of this interface:

Either choice is fine. The example in this section usesExpatPullParser, via Xml.newPullParser().

Analyze the Feed


The first step in parsing a feed is to decide which fields you're interested in. The parser extracts data for those fields and ignores the rest.

Here is an excerpt from the feed that's being parsed in the sample app. Each post to StackOverflow.com appears in the feed as an entry tag that contains several nested tags:

<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule" ...">
<title type="text">newest questions tagged android - Stack Overflow</title>
...
<entry>
...
</entry>
<entry>
<id>http://stackoverflow.com/q/9439999</id>
<re:rank scheme="http://stackoverflow.com">0</re:rank>
<title type="text">Where is my data file?</title>
<category scheme="http://stackoverflow.com/feeds/tag?tagnames=android&sort=newest/tags" term="android"/>
<category scheme="http://stackoverflow.com/feeds/tag?tagnames=android&sort=newest/tags" term="file"/>
<author>
<name>cliff2310</name>
<uri>http://stackoverflow.com/users/1128925</uri>
</author>
<link rel="alternate" href="http://stackoverflow.com/questions/9439999/where-is-my-data-file" />
<published>2012-02-25T00:30:54Z</published>
<updated>2012-02-25T00:30:54Z</updated>
<summary type="html">
<p>I have an Application that requires a data file...</p> </summary>
</entry>
<entry>
...
</entry>
...
</feed>

The sample app extracts data for the entry tag and its nested tags titlelink, and summary.

Instantiate the Parser


The next step is to instantiate a parser and kick off the parsing process. In this snippet, a parser is initialized to not process namespaces, and to use the provided InputStream as its input. It starts the parsing process with a call to nextTag() and invokes the readFeed() method, which extracts and processes the data the app is interested in:

public class StackOverflowXmlParser {
// We don't use namespaces
private static final String ns = null; public List parse(InputStream in) throws XmlPullParserException, IOException {
try {
XmlPullParser parser = Xml.newPullParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
parser.setInput(in, null);
parser.nextTag();
return readFeed(parser);
} finally {
in.close();
}
}
...
}

Read the Feed


The readFeed() method does the actual work of processing the feed. It looks for elements tagged "entry" as a starting point for recursively processing the feed. If a tag isn't an entry tag, it skips it. Once the whole feed has been recursively processed, readFeed() returns a List containing the entries (including nested data members) it extracted from the feed. This List is then returned by the parser.

private List readFeed(XmlPullParser parser) throws XmlPullParserException, IOException {
List entries = new ArrayList(); parser.require(XmlPullParser.START_TAG, ns, "feed");
while (parser.next() != XmlPullParser.END_TAG) {
if (parser.getEventType() != XmlPullParser.START_TAG) {
continue;
}
String name = parser.getName();
// Starts by looking for the entry tag
if (name.equals("entry")) {
entries.add(readEntry(parser));
} else {
skip(parser);
}
}
return entries;
}

Parse XML


The steps for parsing an XML feed are as follows:

  1. As described in Analyze the Feed, identify the tags you want to include in your app. This example extracts data for the entry tag and its nested tags titlelink, and summary.
  2. Create the following methods:
    • A "read" method for each tag you're interested in. For example, readEntry()readTitle(), and so on. The parser reads tags from the input stream. When it encounters a tag named entrytitlelink orsummary, it calls the appropriate method for that tag. Otherwise, it skips the tag.
    • Methods to extract data for each different type of tag and to advance the parser to the next tag. For example:
      • For the title and summary tags, the parser calls readText(). This method extracts data for these tags by calling parser.getText().
      • For the link tag, the parser extracts data for links by first determining if the link is the kind it's interested in. Then it uses parser.getAttributeValue() to extract the link's value.
      • For the entry tag, the parser calls readEntry(). This method parses the entry's nested tags and returns an Entry object with the data members titlelink, and summary.
    • A helper skip() method that's recursive. For more discussion of this topic, see Skip Tags You Don't Care About.

This snippet shows how the parser parses entries, titles, links, and summaries.

public static class Entry {
public final String title;
public final String link;
public final String summary; private Entry(String title, String summary, String link) {
this.title = title;
this.summary = summary;
this.link = link;
}
} // Parses the contents of an entry. If it encounters a title, summary, or link tag, hands them off
// to their respective "read" methods for processing. Otherwise, skips the tag.
private Entry readEntry(XmlPullParser parser) throws XmlPullParserException, IOException {
parser.require(XmlPullParser.START_TAG, ns, "entry");
String title = null;
String summary = null;
String link = null;
while (parser.next() != XmlPullParser.END_TAG) {
if (parser.getEventType() != XmlPullParser.START_TAG) {
continue;
}
String name = parser.getName();
if (name.equals("title")) {
title = readTitle(parser);
} else if (name.equals("summary")) {
summary = readSummary(parser);
} else if (name.equals("link")) {
link = readLink(parser);
} else {
skip(parser);
}
}
return new Entry(title, summary, link);
} // Processes title tags in the feed.
private String readTitle(XmlPullParser parser) throws IOException, XmlPullParserException {
parser.require(XmlPullParser.START_TAG, ns, "title");
String title = readText(parser);
parser.require(XmlPullParser.END_TAG, ns, "title");
return title;
} // Processes link tags in the feed.
private String readLink(XmlPullParser parser) throws IOException, XmlPullParserException {
String link = "";
parser.require(XmlPullParser.START_TAG, ns, "link");
String tag = parser.getName();
String relType = parser.getAttributeValue(null, "rel");
if (tag.equals("link")) {
if (relType.equals("alternate")){
link = parser.getAttributeValue(null, "href");
parser.nextTag();
}
}
parser.require(XmlPullParser.END_TAG, ns, "link");
return link;
} // Processes summary tags in the feed.
private String readSummary(XmlPullParser parser) throws IOException, XmlPullParserException {
parser.require(XmlPullParser.START_TAG, ns, "summary");
String summary = readText(parser);
parser.require(XmlPullParser.END_TAG, ns, "summary");
return summary;
} // For the tags title and summary, extracts their text values.
privateString readText(XmlPullParser parser)throwsIOException,XmlPullParserException{
String result ="";
if(parser.next()==XmlPullParser.TEXT){ result
= parser.getText(); parser
.nextTag();
}
return result;
}
...
}

Skip Tags You Don't Care About


One of the steps in the XML parsing described above is for the parser to skip tags it's not interested in. Here is the parser's skip() method:

private void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
if (parser.getEventType() != XmlPullParser.START_TAG) {
throw new IllegalStateException();
}
int depth = 1;
while (depth != 0) {
switch (parser.next()) {
case XmlPullParser.END_TAG:
depth--;
break;
case XmlPullParser.START_TAG:
depth++;
break;
}
}
}

This is how it works:

  • It throws an exception if the current event isn't a START_TAG.
  • It consumes the START_TAG, and all events up to and including the matching END_TAG.
  • To make sure that it stops at the correct END_TAG and not at the first tag it encounters after the originalSTART_TAG, it keeps track of the nesting depth.

Thus if the current element has nested elements, the value of depth won't be 0 until the parser has consumed all events between the original START_TAG and its matching END_TAG. For example, consider how the parser skips the <author> element, which has 2 nested elements, <name> and <uri>:

  • The first time through the while loop, the next tag the parser encounters after <author> is theSTART_TAG for <name>. The value for depth is incremented to 2.
  • The second time through the while loop, the next tag the parser encounters is the END_TAG </name>. The value for depth is decremented to 1.
  • The third time through the while loop, the next tag the parser encounters is the START_TAG <uri>. The value for depth is incremented to 2.
  • The fourth time through the while loop, the next tag the parser encounters is the END_TAG </uri>. The value for depth is decremented to 1.
  • The fifth time and final time through the while loop, the next tag the parser encounters is the END_TAG</author>. The value for depth is decremented to 0, indicating that the <author> element has been successfully skipped.

Consume XML Data


The example application fetches and parses the XML feed within an AsyncTask. This takes the processing off the main UI thread. When processing is complete, the app updates the UI in the main activity (NetworkActivity).

In the excerpt shown below, the loadPage() method does the following:

  • Initializes a string variable with the URL for the XML feed.
  • If the user's settings and the network connection allow it, invokes new DownloadXmlTask().execute(url). This instantiates a new DownloadXmlTask object (AsyncTasksubclass) and runs its execute() method, which downloads and parses the feed and returns a string result to be displayed in the UI.
public class NetworkActivity extends Activity {
public static final String WIFI = "Wi-Fi";
public static final String ANY = "Any";
private static final String URL = "http://stackoverflow.com/feeds/tag?tagnames=android&sort=newest"; // Whether there is a Wi-Fi connection.
private static boolean wifiConnected = false;
// Whether there is a mobile connection.
private static boolean mobileConnected = false;
// Whether the display should be refreshed.
public static boolean refreshDisplay = true;
public static String sPref = null; ... // Uses AsyncTask to download the XML feed from stackoverflow.com.
public void loadPage() { if((sPref.equals(ANY)) && (wifiConnected || mobileConnected)) {
new DownloadXmlTask().execute(URL);
}
else if ((sPref.equals(WIFI)) && (wifiConnected)) {
new DownloadXmlTask().execute(URL);
} else {
// show error
}
}

The AsyncTask subclass shown below, DownloadXmlTask, implements the following AsyncTask methods:

  • doInBackground() executes the method loadXmlFromNetwork(). It passes the feed URL as a parameter. The method loadXmlFromNetwork() fetches and processes the feed. When it finishes, it passes back a result string.
  • onPostExecute() takes the returned string and displays it in the UI.
// Implementation of AsyncTask used to download XML feed from stackoverflow.com.
private class DownloadXmlTask extends AsyncTask<String, Void, String> {
@Override
protected String doInBackground(String... urls) {
try {
return loadXmlFromNetwork(urls[0]);
} catch (IOException e) {
return getResources().getString(R.string.connection_error);
} catch (XmlPullParserException e) {
return getResources().getString(R.string.xml_error);
}
} @Override
protected void onPostExecute(String result) {
setContentView(R.layout.main);
// Displays the HTML string in the UI via a WebView
WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.loadData(result, "text/html", null);
}
}

Below is the method loadXmlFromNetwork() that is invoked from DownloadXmlTask. It does the following:

  1. Instantiates a StackOverflowXmlParser. It also creates variables for a List of Entry objects (entries), and titleurl, and summary, to hold the values extracted from the XML feed for those fields.
  2. Calls downloadUrl(), which fetches the feed and returns it as an InputStream.
  3. Uses StackOverflowXmlParser to parse the InputStreamStackOverflowXmlParser populates aList of entries with data from the feed.
  4. Processes the entries List, and combines the feed data with HTML markup.
  5. Returns an HTML string that is displayed in the main activity UI by the AsyncTask methodonPostExecute().
// Uploads XML from stackoverflow.com, parses it, and combines it with
// HTML markup. Returns HTML string.
private String loadXmlFromNetwork(String urlString) throws XmlPullParserException, IOException {
InputStream stream = null;
// Instantiate the parser
StackOverflowXmlParser stackOverflowXmlParser = new StackOverflowXmlParser();
List<Entry> entries = null;
String title = null;
String url = null;
String summary = null;
Calendar rightNow = Calendar.getInstance();
DateFormat formatter = new SimpleDateFormat("MMM dd h:mmaa"); // Checks whether the user set the preference to include summary text
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
boolean pref = sharedPrefs.getBoolean("summaryPref", false); StringBuilder htmlString = new StringBuilder();
htmlString.append("<h3>" + getResources().getString(R.string.page_title) + "</h3>");
htmlString.append("<em>" + getResources().getString(R.string.updated) + " " +
formatter.format(rightNow.getTime()) + "</em>"); try {
stream = downloadUrl(urlString);
entries = stackOverflowXmlParser.parse(stream);
// Makes sure that the InputStream is closed after the app is
// finished using it.
} finally {
if (stream != null) {
stream.close();
}
} // StackOverflowXmlParser returns a List (called "entries") of Entry objects.
// Each Entry object represents a single post in the XML feed.
// This section processes the entries list to combine each entry with HTML markup.
// Each entry is displayed in the UI as a link that optionally includes
// a text summary.
for (Entry entry : entries) {
htmlString.append("<p><a href='");
htmlString.append(entry.link);
htmlString.append("'>" + entry.title + "</a></p>");
// If the user set the preference to include summary text,
// adds it to the display.
if (pref) {
htmlString.append(entry.summary);
}
}
return htmlString.toString();
} // Given a string representation of a URL, sets up a connection and gets
// an input stream.
private InputStream downloadUrl(String urlString) throws IOException {
URL url = new URL(urlString);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(10000 /* milliseconds */);
conn.setConnectTimeout(15000 /* milliseconds */);
conn.setRequestMethod("GET");
conn.setDoInput(true);
// Starts the query
conn.connect();
return conn.getInputStream();
}

官方XmlPullParser和网络解析xml示例及详述的更多相关文章

  1. MsXml创建和解析XML示例

    一.MsXml创建XML文档示例 // XmlCreationDemo.cpp #include <stdlib.h> #include <stdio.h> // 引入MSXM ...

  2. Android DOM解析XML示例程序

    DOM方式解析xml是先把xml文档都读到内存中,然后再用DOM API来访问树形结构,并获取数据的.DOM比较符合人的思维模式,但是其对内存的消耗比较大. activity_main.xml < ...

  3. Stax解析XML示例代码

    package org.itat.stax; import java.io.IOException; import java.io.InputStream; import javax.xml.pars ...

  4. 四种生成和解析XML文档的方法详解(介绍+优缺点比较+示例)

    众所周知,现在解析XML的方法越来越多,但主流的方法也就四种,即:DOM.SAX.JDOM和DOM4J 下面首先给出这四种方法的jar包下载地址 DOM:在现在的Java JDK里都自带了,在xml- ...

  5. Android网络之数据解析----SAX方式解析XML数据

    ​[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/ ...

  6. iOS开发网络篇—XML数据的解析

     iOS开发网络篇—XML数据的解析 iOS开发网络篇—XML介绍 一.XML简单介绍 XML:全称是Extensible Markup Language,译作“可扩展标记语言” 跟JSON一样,也是 ...

  7. 使用pull方式解析xml文件示例:

    网上的示例太多,基本类似,个人在此做个简单的总结: 1.首先在工程的asserts目录下建一个book.xml文件: <?xml version="1.0" encoding ...

  8. Android开发学习---使用XmlPullParser解析xml文件

    Android中解析XML的方式主要有三种:sax,dom和pull关于其内容可参考:http://blog.csdn.net/liuhe688/article/details/6415593 本文将 ...

  9. ACEXML解析XML文件——简单示例程序

    掌握了ACMXML库解析XML文件的方法后,下面来实现一个比较完整的程序. 定义基本结构 xml文件格式如下 <?xml version="1.0"?> <roo ...

随机推荐

  1. hibernate查询之Criteria实现分页方法(GROOVY语法)

    public int searchTest(String name, Integer pageIndex, List<Test> resultList){ def criteria = T ...

  2. Dom对象的经常用法

    Dom对象的经常用法: (1)getElementById() 查询给定ID属性值的元素,返回该元素的元素节点 1.  查询给定ID属性值的元素,返回该元素的元素节点.也称为元素对象.        ...

  3. Dropbox电面面经

    他家电面有2轮,等待onsite.. . 电面1: 国人MM面的.这点感觉非常难得. 统计近期5分钟的点击量,实现hit和getHit两个函数.这题是他家高频题,我用deque实现的,hit的均摊时间 ...

  4. LoadRunner中存储表格参数------关联数组

    主要用到 web_reg_save_param_ex函数("Scope=All",), sprintf( CProdNo,"{CProdNo_%d}",i ); ...

  5. 【java报错】CacheLoader returned null for key class

    CacheLoader returned null for key class cmd     mvn eclipse:clean eclipse:eclipse mvn install -Dmave ...

  6. Spring Cloud Sleuth 中id的使用

    Spring Cloud Sleuth采用的是Google的开源项目Dapper的专业术语. Span:基本工作单元,发送一个远程调度任务 就会产生一个Span,Span是一个64位ID唯一标识的,T ...

  7. bzoj 5329 战略游戏

    题目大意: 一个无向图 Q个询问 每次给一些点的集合 求有多少个点满足去掉这个点后使这些点的集合中有一个点对不连通 思路: 点双缩点 相当于每次求这些点中的所有路径上的圆点个数 可以将这些点按dfs序 ...

  8. 【SCOI 2003】 严格n元树

    [题目链接] 点击打开链接 [算法] f[i]表示深度小于等于i的严格n元树 显然,一棵深度小于等于i的严格n元树,就是一个根节点,下面有n棵子树,这n棵子树都是深度小于等于i-1的严格n元树,每棵子 ...

  9. 小程序-demo:快速开始

    ylbtech-小程序-demo:快速开始 1.返回顶部 1.app.js //app.js App({ onLaunch: function () { // 展示本地存储能力 var logs = ...

  10. QT笔记1

    1 第一个就是helloworld窗体啦 #include <qapplication.h> #include <qpushbutton.h> int main( int ar ...