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. 利用Druid实现应用和SQL监控

    一.关于Druid Druid是一个JDBC组件,它包括三部分: DruidDriver 代理Driver,能够提供基于Filter-Chain模式的插件体系. DruidDataSource 高效可 ...

  2. iptables防火墙以及网络协议基本原理

    一. Linux 网络安全模型 1. 防火墙: 工作在主机或者网络边缘,对进出报文使用实现定义的规则进行检测,并且由匹配的规则进行处理的一组硬件或者软件.也可能两者结合. 1) 通常使用的防火墙设备 ...

  3. 运行mapreduce - java.lang.InterruptedException

    错误日志: 2018-11-19 05:23:51,686 WARN [main] util.NativeCodeLoader (NativeCodeLoader.java:<clinit> ...

  4. router-link的a样式变成div样式元素属性

    <router-link tag="div" :to="itemChild.path"><span>{{itemChild.name}} ...

  5. spring实战笔记6---springMVC的请求过程

    之前有一次在面试其中被问到了这个问题.当时说得不是非常清楚,有些细节的地方想不起来了.所以在这里从新回想和总结一下SpringMVC的起步.请求的运行过程. 在SpringMVC其中.跟请求(Requ ...

  6. HDU 1160 FatMouse&#39;s Speed(DP)

    题意  输入n个老鼠的体重和速度   从里面找出最长的序列  是的重量递增时速度递减 简单的DP  令d[i]表示以第i个老鼠为所求序列最后一个时序列的长度  对与每一个老鼠i  遍历全部老鼠j  当 ...

  7. 跟面试官讲Binder(零)

    面试的时候,面试官问你说,简单说一下Android的Binder机制,你会怎么回答? 我想,我会这么说. 在Android启动的时候,Zygote进程孵化出第一个子进程叫SystemServer,而在 ...

  8. Android中View窗口getWidth和getMeasuredWidth的差别

    今天在研究自己定义listview的下拉刷新的效果.想移植到项目需求中,再看自己定义源代码时发现了一个问题就是getWidth和getMeasuredWidth两个方法有什么差别,求教万能的百度,经调 ...

  9. 2 Angular 2 的核心概念

    一.组件(Components): 组件是构成 Angular 应用的基础和核心,它是一个模板的控制类,用于处理应用和逻辑页面的视图部分.组件知道如何渲染自己及配置依赖注入,并通过一些由属性和方法组成 ...

  10. NHibernate不支持复杂的linq,就一定要用DataTable这么低级吗

    有些linq,好不容易写出来,正想扬眉吐屁一番,不料用NHibernate一执行,却报错,说是不支持,我靠. 只好捏着鼻子写一大段sql,交给它.这种直接执行SQL的情况,我看我同事写的,全部都是返回 ...