【Android Training - Connectivity】基本网络操作 [ Lesson 3 - 详解如何解析XML数据 ]
来源:互联网 发布:数据挖掘与r语言 pdf 编辑:程序博客网 时间:2024/05/25 21:33
Parsing XML Data [解析XML数据]
- Extensible Markup Language (XML) .[关于什么是XML就不多介绍了, 它与JSON是最常用到的]. 很多网站或博客上都提供XML feed来记录更新的信息,以便用户进行订阅读取。
- 那么上传[?]与解析XML数据就成了app的一个常见的功能。 这一课会介绍如何解析XML文档并使用他们的数据。[关于如何解析JSON数据,请参考【Android】解析Json 数据示例 ]
- [?]这里很奇怪,为什么是Upload,看文章最后一段代码示例的注释,应该是Download才对,这个地方很有可能是Google编辑写错了,有不同观点的还望指正]
Choose a Parser [选择一个解析器]
- 我们推荐
XmlPullParser
, 它是在Android上一个高效且可维护的解析XML方法。 Android 上有这个接口的两种实现方式:KXmlParser
viaXmlPullParserFactory.newPullParser()
.ExpatPullParser
, viaXml.newPullParser()
.
- 两个选择都是比较好的。下面的示例中是使用
ExpatPullParser
, viaXml.newPullParser()
.
Analyze the Feed [分析Feed]
- 解析一个feed的第一步是决定需要获取哪些字段。这样解析器才去抽取出那些需要的字段而忽视剩下的。
- 下面一段章节概览Sample app中截取的一段代码示例.
<?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>
- 在sample app中抽取了
entry
标签与它的子标签title
,link
,summary
.
Instantiate the Parser [实例化解析器]
下一步就是实例化一个parser并开始解析的操作。请看下面的示例: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 [读取Feed]
The
readFeed()
实际上并没有处理feed的内容。它只是在寻找一个 "entry" 的标签作为递归(recursively)处理整个feed的起点。如果一个标签它不是"entry"
, readFeed()方法会跳过它. 当整个feed都被递归处理后,readFeed()
会返回一个包含了entry标签(包括里面的数据成员)的 List
。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 [解析XML]
解析步骤如下:
- 正如在上面“ 分析Feed”所说的, 判断出你想要的tag。这个example抽取了
entry
标签与它的内部标签title
,link
,summary
. - 创建下面的方法:
- 为每一个你想要获取的标签创建一个 "read" 方法。例如
readEntry()
,readTitle() 等等
. 解析器从input stream中读取tag . 当读取到entry
,title
,link
或者summary
标签时,它会为那些标签调用相应的方法,否则,跳过这个标签。 - 为每一个不同的标签的提取数据方法进行优化,例如:
- 对于
title
andsummary
tags, 解析器调用readText()
. 通过调用parser.getText()
.来获取返回数据。 - 对于
link
tag,解析器先判断这个link是否是我们想要的类型,然后再读取数据。可以使用parser.getAttributeValue()
来获取返回数据。 - 对于
entry
tag, 解析起调用readEntry()
. 这个方法解析entry的内部标签并返回一个带有title
,link
, andsummary
数据成员的Entry对象。
- 对于
- 一个帮助方法:
skip()
. 关于这部分的讨论,请看下面一部分内容:Skip Tags You Don't Care About
- 为每一个你想要获取的标签创建一个 "read" 方法。例如
下面的代码演示了如何解析 entries, titles, links, 与 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.private String readText(XmlPullParser parser) throws IOException, XmlPullParserException { String result = ""; if (parser.next() == XmlPullParser.TEXT) { result = parser.getText(); parser.nextTag(); } return result;} ...}
Skip Tags You Don't Care About [跳过你不在意标签]
- 下面演示解析器的
skip()
方法:
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; } } }
- 上面这个方法是如何工作的呢?【下面的就不翻译了】
- 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 matchingEND_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.
- It throws an exception if the current event isn't a
- 因此如果目前的标签有子标签,
depth
的值就不会为 0,直到解析器已经处理了所有位于START_TAG
与END_TAG
之间的事件。例如,看解析器如何跳过<author>
标签,它有2个子标签,<name>
与<uri>:
- The first time through the
while
loop, the next tag the parser encounters after<author>
is theSTART_TAG
for<name>
. The value fordepth
is incremented to 2. - The second time through the
while
loop, the next tag the parser encounters is theEND_TAG
</name>
. The value fordepth
is decremented to 1. - The third time through the
while
loop, the next tag the parser encounters is theSTART_TAG
<uri>
. The value fordepth
is incremented to 2. - The fourth time through the
while
loop, the next tag the parser encounters is theEND_TAG
</uri>
. The value fordepth
is decremented to 1. - The fifth time and final time through the
while
loop, the next tag the parser encounters is theEND_TAG
</author>
. The value fordepth
is decremented to 0, indicating that the<author>
element has been successfully skipped.
- The first time through the
Consume XML Data [使用XML数据]
示例程序是在 AsyncTask
中获取与解析XML数据的。当获取到数据后,程序会在main activity(NetworkActivity
)里面进行更新操作。
在下面示例代码中,loadPage()
方法做了下面的事情:
- 初始化一个带有URL地址的String变量,用来订阅XML feed。
- 如果用户设置与网络连接都允许,会触发
new DownloadXmlTask().execute(url)
. 这会初始化一个新的DownloadXmlTask(
对象并且开始执行它的AsyncTask
subclass)execute()
方法。
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 } }下面是DownloadXmlTask是怎么工作的:
// 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); }}下面是loadXmlFromNetwork是怎么工作的:
// Uploads XML from stackoverflow.com, parses it, and combines it with// HTML markup. Returns HTML string.【这里可以看出应该是Download】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.【关于Timeout具体应该设置多少,可以借鉴这里的数据,当然前提是一般情况下】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(); InputStream stream = conn.getInputStream(); }
学习自:http://developer.android.com/training/basics/network-ops/xml.html,请多指教,谢谢!
转载请注明作者与出自:http://blog.csdn.net/kesenhoo,谢谢配合!
- 【Android Training - Connectivity】基本网络操作 [ Lesson 3 - 详解如何解析XML数据 ]
- 【Android Training - Connectivity】基本网络操作 [ Lesson 0 - 章节概览 ]
- 【Android Training - Connectivity】基本网络操作 [ Lesson 1 - 如何连接到网络的经典示例 ]
- 【Android Training - Connectivity】基本网络操作 [ Lesson 2 - 管理网络连接的常用方法 ]
- 【Android Training - Connectivity】优化下载的效率[Lesson 1 - 看无线电波如何影响网络操作]
- Android Training - 网络操作(3) - 解析XML数据
- 【Android Advanced Training - 05】传输数据时避免电量的浪费[Lesson 1 - 看无线电波如何影响网络操作]
- 【Android Training - Connectivity】优化下载的效率[Lesson 4 - 根据网络类型更改下载模式]
- 【Android Training - Connectivity】优化下载的效率[Lesson 3 - 使用缓存来避免重复的下载]
- Android官方开发文档Training系列课程中文版:网络操作之XML解析
- 【Android Training - Connectivity】优化下载的效率[Lesson 0 - 章节概览]
- Android网络数据xml解析
- android XML数据解析详解
- 【Android Training - Connectivity】优化下载的效率[Lesson 2 - 调整定时更新的频率(C2DM与退避算法)]
- 【Android Training - 04】保存数据 [ Lesson 3 - 保存数据到SQLite]
- 【Android Training - Performance】优化电池续航能力[Lesson 3 - 判断并监测网络连接状态]
- 【Android Advanced Training - 05】传输数据时避免电量的浪费[Lesson 4 - 根据网络类型更改下载模式]
- 【Android Training - 01】详解Activity生命周期 [ Lesson 3 - 停止与重启Activity ]
- 防止蜘蛛拖垮服务器 - Linux下Apache并发连接数
- 【转】PLSQL中显式Cursor、隐式Cursor、动态Ref Cursor区别
- linux 创建连接命令 ln -s 软链接
- OUI-10133:Invalid staging area. OEM 11g grid control installer error
- Office 2007-2010 文件默認讓 2003打開
- 【Android Training - Connectivity】基本网络操作 [ Lesson 3 - 详解如何解析XML数据 ]
- CImage类(转)
- 分享45个android实例源码,很好很强大
- Oracle的锁表与解锁
- C++Primer观后感(一)
- MATLAB批量读取文件夹的图片
- eclipse 项目
- [C陷阱]getchar的返回值是int而不是char
- 利用Sqoop将数据从数据库导入到HDFS(转)