本文对Android中的XML解析进行了简单介绍。本文没有详细说明XML的相关内容。阅读本文之前,开发人员必须了解XML。本文针对各种类型的XML解析描述了Android中可用包的相关内容,并在结尾处提供了展示KXML解析器方法的示例代码片段。
范围:
本文旨在针对希望开发使用XML的手机应用程序的 Android开发人员而设计。本文假定开发人员已掌握Android、Java编程语言和XML。本文着重介绍XML解析的相关内容,并由此阐述不在本文档介绍范围之内的Android技术和XML。
如欲了解更多Android的相关内容,请参阅三星移动创新者园地(SMI)的知识库。
http://innovator.samsungmobile.com/cn/platform.main.do?platformId=1
简介
XML是一种在无更多人类或机器智能的情况下,以可进行处理的格式来表示文本和数据的一种方法。XML中已编排格式的信息可在各种平台、语言以及应用程序中进行交换,并可通过各种开发工具和实用程序加以使用。
XML的设计目标是强调在互联网中的简单性、通用性和可用性。Android支持通过XML应用程序编程接口(API)来处理XML语言。
本文说明了Android中可用于XML处理的各种API。本文假定开发人员已配备有Eclipse IDE,并掌握了Android、Java编程语言和XML。
XML解析器
XML解析具有多种类型
1. 树状模型解析器
A. 文档对象模型:
文档对象模型(DOM)解析器是一种树状模型解析器。DOM解析器可通读整个文档,在内存中建立整个XML文档显示,然后向调用程序交付整个内存块。DOM解析器占据了大量的内存。
2. 基于流的解析器(基于事件)
A. Push Parser(推模式解析器)
推模式解析器可通读文档,并且当该解析器遭遇XML中的元素时,其可通过回调方法(监听器对象)通知该应用程序。SAX解析器是此推模式解析器的其中一个示例。
B. Pull Parser(拉模式解析器):
拉模式解析器与推模式解析器相对。该解析器仅当应用程序要求时方可提供数据。应用程序通过重复请求下一步来驱动解析器通过文档。拉模式解析器的示例为StAX API。
3.数据绑定XML解析器
XML处理API的另一种形式是XML数据绑定,其中,与文档对象模型解析器创建的通用对象相比,XML数据可用作定制层级和强化类型的类。
Java的XML简单API和文档对象模型(DOM)在Android中均可使用。多年来,此两种API已成为Java技术的一部分。Android中无新款XML流媒体API。但是,Android提供了一个功能相同的库。最终,Java XML绑定API在Android中同样无法使用。该API必定在Android中执行.
依据应用程序和XML文档的特点,哪个解析器可在应用程序中使用?
SAX解析器
SAX是一种事件驱动的词汇界面,在该界面上可连续阅读文档,并且其内容可报告用来回调用户设计的句柄对象中的各种方法。SAX可快速有效地执行,但却难以用来从XML中随机提取信息,因为其易于在跟踪了解正在处理的文档部分的情况下使应用程序作者承担负重。
SAX解析器在Android javax.xml.parsers包中可使用。您可以从Java环境原封不动地使用SAX API,而无需作出特别修改进行运行。
SAX解析器的创建通过使用
javax.xml.parsers包中存在的
SAXParser和
SAXParserFactory类以及
org.xml.sax包中存在的
XMLReader类来完成。
/* Create a URL we want to load some xml-data from. */
URL url = new URL("http://example.com/example.xml");
/* Get a SAXParser from the SAXPArserFactory. */
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = spf.newSAXParser();
/* Get the XMLReader of the SAXParser we created. */
XMLReader xr = sp.getXMLReader();
/* Create a new ContentHandler and apply it to the XML-Reader*/
MyDefaultHandler myDefaultHandler = new MyDefaultHandler();
/*set Content Handlet*/
xr.setContentHandler(myDefaultHandler );
/* Parse the xml-data from our URL. */
URL url = new URL("http://innovator.samsungmobile
.com/servlet/rss/samsung_s60_symbian_best.xml?platformId=1");
xr.parse(new InputSource(url.openStream()));
/* Parsing has finished. */
OR
/* Parse the xml-data from InputSource. */
String xmlStringContent = "test";
InputSource is = new InputSource();
is.setCharacterStream(new StringReader(xmlStringContent));
xr.parse(is);
如同执行任何SAX一样,大部分详细内容位于SAX句柄中。当穿过XML文档时,该句柄从SAX解析器接收事件。Android中的句柄为在
org.xml.sax.helpers包中可使用的
DefaultHandler。
开发人员需要创建可扩展
org.xml.sax.helpers.DefaultHandler的处理程序,并需重载与SAX解析器所提出事件相对应的必要的方法。需要重载的必要的方法为
public void startDocument() throws SAXException {}
public void endDocument() throws SAXException {}
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {}
public void endElement(String uri, String localName, String qName) throws SAXException {}
public void characters(char[] ch, int start, int length) throws SAXException {}
在每个文档的开始/结尾处均可调用
startDocument()和
endDocument()方法。
例如,当解析器到达起始标签时,
startElement()可获调用。在此情况下,localName将为“platformId”。属性变量将持有任何相关联的属性信息:atts.getValue("name")将返回“Android”。
例如,当解析器到达结束标签时,
endElement()方法可获调用。在此情况下,localName将为“platformId”。
在起始标签与结束标签中间,可能存在一个字符串,如<platformId name=“Android”>1</platformId>。SAXParser每次可读取字符串中的一个字符,而且可对处理程序
characters()方法的方法调用进行缓冲。
Android SAX解析器
除Java SAX API之外,Android还提供了一个框架,可轻松写入有效且耐用的SAX句柄。Android SAX解析器框架存在于
android.sax包中。
android.sax包中包含了5个界面(即
ElementListener、EndElementListener、EndTextElementListener, StartElementListener和TextElementListener)以及2个类(即
Element和RootElement)。
Android SAX解析器框架可使您建立XML文档结构模型,并根据需要添加一个事件监听器。如欲创建一个SAX内容句柄,首先需要使用
RootElement和
Element类来描述您所感兴趣的XML的结果。
例如,解析一个如下< /p>所示的xml文件
<rss version="2.0
<item>
<title>test
<pubDate>Sun, 15 Jun 2000 14:13:46 +0200
<info
url="http://xyz.com/abc.ogg"
fileSize="37506213" type="application/ogg">
</item>
</rss>
以上的XML拥有
title、pubDate和
info作为元素,此类元素位于项目元素起始标签和结束标签之间,并定义其为每个
item元素的子元素。同样,此类项目元素也是
rss元素的子元素。
声明您的xml拥有一个称之为rss的根元素
RootElement root = new RootElement("rss");
然后使用RootElement 类的requireChild()方法来声明我们感兴趣的每个item和info子元素。
Element item = root.requireChild("item");
Element info = item.requireChild("info");
接下来,为您所希望抓取的每个元素设置部分‘监听器’。对于每个监听器,您需使用一个可执行您所感兴趣的界面的anonymous inner class(匿名内部类)(
EndElementListner或
EndTextElementListener)。注意,无需跟踪了解字符数据。这样不仅更加简便,而且实际上更加有效。
最后,当一切准备就绪时,创建SAX内容句柄,并将其和inputStream传递进入存在于
android.util包中的
XML.parse()方法。
/* Parse the xml-data from our URL. */
URL url = new URL("http://xyz.com/.../");
InputStream inputStream = url.openStream();
Xml.parse(inputStream, Xml.Encoding.UTF-8, root.getContentHandler());
DOM解析器
DOM解析器将整个XML文档读入内存,然后可允许您使用DOM API来遍历XML树,从而可检索您所需的数据。
在
javax.xml.parsers的包中提供了有关Android的DOM解析。SAX解析器使用了相同的包。使用
javax.xml.parsers.DocumentBuilderFactory类来完成创建DOM XML解析器。
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
try {
/* Parse the xml-data from our URL. */
URL url = new URL("http://xyz.com/.../");
InputStream inputStream = url.openStream();
/*Get Document Builder*/
DocumentBuilder builder = builderFactory.newDocumentBuilder();
Document dom = builder.parse(inputStream);
} catch (Exception e) { }
一旦已获取DOM对象,您即可开始遍历XML中存在的元素和属性。使用
org.w3c.dom包中存有的界面来完成存取XML的元素和属性。
DOM对象包含树状结构中所连接的许多不同的节点。位于顶部的是文档对象。该文档对象拥有一个简单的根元素,其可通过调用
getDocumentElement()来予以返回。
Element rootElement = dom.getDocumentElement();
根元素具有子元素,其可能为元素、注释、处理指令以及字符等。您可获取元素的子元素,如下:
NodeList items = root.getElementsByTagName(ITEM);
按文档顺序返回带有给定标签名称的所有后代元素的NodeList。然后,可获取后继节点,如下
Node item = items.item(i);
NodeList界面提供了节点有序采集的抽象过程。可通过整数指数(自0开始)来存取NodeList中的节点。
for (int i=0;i<items.getLength();i++) {
Node item = items.item(i);
NodeList properties = item.getChildNodes();
for (int j=0;j<properties.getLength();j++){
Node property = properties.item(j);
String name = property.getNodeName();
}
}
使用
getChildNodes()方法可获取此节点的子节点的列表。此子节点可返回作为新的NodeList对象。NodeList类中存在的一种方法即
getLength()方法,可用于获取子节点的数量,从而对它们进行循环访问。
拉模式解析器
Android对Java的StAX API不提供支持。但是,Android确定与工作方式类似于StAX的拉模式解析器()一起提供。
拉模式解析器存在于
org.xmlpull.v1包中。它可使您的应用程序代码从解析器中拉动或寻求事件,而SAX解析器自动将事件推入句柄,正好与其相反。
拉模式解析器可使用存在于
android.util包中的XML类来创建。
XmlPullParser parser = Xml.newPullParser();
尽管拉模式解析器工作方式类似于SAX parser,但是,您必须使用parser.next()和nextToken()方法来从其进行拉动。当next()提供访问高级别的解析事件时,nextToken()可允许使用低级别的符号。
解析器的当前事件状态可通过调用
getEventType()方法来确定。起初,该解析器处于
START_DOCUMENT状态。
next()方法将解析器推进到下一个事件。从下一个事件中返回的int值可确定当前的解析器状态,并等于从接下来对
getEventType()调用的过程中已返回的值。
以下事件类型可通过
next()方法来查看。
START_TAG
读取XML起始标签。
TEXT 文本
读取文本内容;文本内容可使用getText()方法来进行检索。(当验证模式时,next()将不会使用nextToken() instead来报告可忽略的空白分隔符)
END_TAG
读取结束标签
END_DOCUMENT
无更多的事件可用
nextToken()可提供访问文档结构的详细内容,包括诸如处理指令、注释、实体引用等要素。
XmlPullParser parser = Xml.newPullParser();
try {
/* Parse the xml-data from our URL. */
URL url = new URL("http://xyz.com/.../");
InputStream inputStream = url.openStream();
/*auto detect*/
parser.setInput(this.getInputStream(), null);
int eventType = parser.getEventType();
boolean done = false;
while (eventType != XmlPullParser.END_DOCUMENT && !done){
switch (eventType){
case XmlPullParser.START_DOCUMENT:
//process
break;
case XmlPullParser.START_TAG:
String name = parser.getName();
if (name.equalsIgnoreCase(ITEM)){
//process
}
break;
case XmlPullParser.END_TAG:
//when done with the processing set done to true.
done = true;
break;
}
eventType = parser.next();
}
XmlResourceParser
Android拥有其自己的XML拉模式解析器,即XmlResourceParser,特别定制用于有效地解析其编制的内部XML格式. XmlResourceParser是一种存在于android.content.res包中的界面。
XmlResourceParser是一个标准的XmlPullParser界面。同时其也是一个已扩展的AttributeSet界面,当完成读取资源时,可向客户端显示此界面中的一种附加的close()方法。
如欲使用该解析器,在res文件夹中创建xml文件夹。创建一个实例,并将其传递进入存在于res/xml文件夹中的数据文件资源中。
XmlResourceParser xrp = activity.getResources().getXml(R.xml.myxml);
此处R.xml.test表示存在于res/xml文件夹中的myxml.xml文件。已返回的XmlResourceParser是XmlPullParser的一个实例,并且其还可执行java. util.AttributeSet。
XmlResourceParser是一种拉模式解析器,其工作方式非常接近拉模式解析器。
XmlResourceParser xrp = activity.getResources().getXml(R.xml.myxml);
xrp.next();
int eventType = xrp.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
if(eventType == XmlPullParser.START_DOCUMENT) {
} else if(eventType == XmlPullParser.START_TAG) {
} else if(eventType == XmlPullParser.END_TAG) {
} else if(eventType == XmlPullParser.TEXT) {
}
eventType = xrp.next();
}
示例程序
以下示例程序给出解析器用法的各种类型
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="samsung.parsers.xml"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="2" />
<uses-permission android:name="android.permission.INTERNET">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".XMLParser" android:label="XMLParser">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".MessageList" android:label="RSS-FEEDS">
<intent-filter>
<category android:name="android.intent.category.SAMPLE_CODE" />
</intent-filter>
</activity>
</application>
</manifest>
文件储存在res/layout文件夹中
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<Button android:text="SAX"
android:id="@+id/buttonSAX"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:layout_gravity="center">
</Button>
<Button android:text="Android SAX"
android:id="@+id/buttonAndroidSAX"
android:layout_height="wrap_content"
android:layout_width="fill_parent">
</Button>
<Button android:text="DOM"
android:id="@+id/buttonDOM"
android:layout_height="wrap_content"
android:layout_width="match_parent">
</Button>
<Button android:text="XML Pull"
android:id="@+id/buttonXMLPull"
android:layout_height="wrap_content"
android:layout_width="match_parent">
</Button>
<Button android:text="XMLResourceParser"
android:id="@+id/buttonXMLResource"
android:layout_height="wrap_content"
android:layout_width="match_parent">
</Button>
</LinearLayout>
row.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/TextView01" android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
xmlPage.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ListView android:id="@+id/android:list"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/></LinearLayout>
创建res/xml文件夹并将myxml.xml放入该文件夹中。
myxml.xml
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
<channel>
<title>android_news
<description>android_news
<link>http://www.xyz.com/android.php
<lastBuildDate>Thu, 12 May 2011 11:28:03 +0100
<item>
<title>How To create Hello World
<link>http://www.xyz.com/android/How To create Hello World
<description>This document shows how to create
<pubDate>Sun, 21 Oct 2010 02:15:41 +0200
</item>
</channel>
</rss>
文件将出现在scr文件夹中。
XMLParser.java
package samsung.parsers.xml;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;public class XMLParser extends Activity implements OnClickListener{
private Button btnSAX;
private Button btnAndroidSAX;
private Button btnDOM;
private Button btnXMLPull;
private Button btnXMLResource;public static final String PARSER_TYPE = "ParserType";public static final int CLASSIC_SAX = 1;
public static final int ANDROID_SAX = 2;
public static final int DOM = 3;
public static final int XML_PULL = 4;
public static final int XMLRESOURCEPARSER = 5;
public static final String RSS = "rss";
// names of the XML tags
public static final String CHANNEL = "channel";
public static final String PUB_DATE = "pubDate";
public static final String DESCRIPTION = "description";
public static final String LINK = "link";
public static final String TITLE = "title";
public static final String ITEM = "item";/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
btnSAX = (Button)findViewById(R.id.buttonSAX);
btnSAX.setOnClickListener(this);
btnAndroidSAX = (Button)findViewById(R.id.buttonAndroidSAX);
btnAndroidSAX.setOnClickListener(this);
btnDOM = (Button)findViewById(R.id.buttonDOM);
btnDOM.setOnClickListener(this);
btnXMLPull = (Button)findViewById(R.id.buttonXMLPull);
btnXMLPull.setOnClickListener(this);
btnXMLResource = (Button)findViewById(R.id.buttonXMLResource);
btnXMLResource.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if(v == btnSAX) {
Intent intent = new Intent(this.getApplication(),MessageList.class);
intent.putExtra(PARSER_TYPE, CLASSIC_SAX);
startActivity(intent);
}else
if(v == btnAndroidSAX) {
Intent intent = new Intent(this.getApplication(),MessageList.class);
intent.putExtra(PARSER_TYPE, ANDROID_SAX);
startActivity(intent);
}else
if(v == btnDOM) {
Intent intent = new Intent(this.getApplication(),MessageList.class);
intent.putExtra(PARSER_TYPE, DOM);
startActivity(intent);
}else
if(v == btnXMLPull) {
Intent intent = new Intent(this.getApplication(),MessageList.class);
intent.putExtra(PARSER_TYPE, XML_PULL);
startActivity(intent);
}else
if(v == btnXMLResource) {
Intent intent = new Intent(this.getApplication(),MessageList.class);
intent.putExtra(PARSER_TYPE, XMLRESOURCEPARSER);
startActivity(intent);
}
}
}
MessageList.java
package samsung.parsers.xml;
import java.io.InputStream;
import java.io.StringWriter;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlSerializer;
import android.app.ListActivity;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.os.Bundle;
import android.util.Log;
import android.util.Xml;
import android.widget.ArrayAdapter;public class MessageList extends ListActivity{
private List messages;
private URL feedURL;
private URLConnection feedURLConnection;
private InputStream is;
public static final String feedUrl = "http://www.androidster.com/android_news.rss";
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.xmlpage);
Bundle extras = getIntent().getExtras();
int value = extras.getInt(XMLParser.PARSER_TYPE);
if(value!= XMLParser.XMLRESOURCEPARSER) {
try {
feedURL = new URL(feedUrl);
feedURLConnection = feedURL.openConnection();
is = feedURLConnection.getInputStream();
} catch (Exception e) {
throw new RuntimeException(e);
}
if(value == XMLParser.CLASSIC_SAX)
loadSAXFeed();
else if(value == XMLParser.ANDROID_SAX)
loadAndroidSAXFeed();
else if(value == XMLParser.DOM)
loadDOMFeed();
else if(value == XMLParser.XML_PULL)
loadXMLPullFeed();
} else
if(value == XMLParser.XMLRESOURCEPARSER)
loadXMLResourceParser();
}private void loadXMLResourceParser(){
try {
Resources res = this.getResources();
XmlResourceParser parser = res.getXml(R.xml.myxml);
parser.next();
int eventType = parser.getEventType();
Message currentMessage = null;
boolean done = false;
while (eventType != XmlPullParser.END_DOCUMENT && !done){
String name = null;
switch (eventType){
case XmlPullParser.START_DOCUMENT:
messages = new ArrayList();
break;
case XmlPullParser.START_TAG:
name = parser.getName();
if (name.equalsIgnoreCase(XMLParser.ITEM)){
currentMessage = new Message();
} else if (currentMessage != null){
if (name.equalsIgnoreCase(XMLParser.LINK)){
currentMessage.setLink(parser.nextText());
} else if (name.equalsIgnoreCase(XMLParser.DESCRIPTION)){
currentMessage.setDescription(parser.nextText());
} else if (name.equalsIgnoreCase(XMLParser.PUB_DATE)){
currentMessage.setDate(parser.nextText());
} else if (name.equalsIgnoreCase(XMLParser.TITLE)){
currentMessage.setTitle(parser.nextText());
}
}
break;
case XmlPullParser.END_TAG:
name = parser.getName();
if (name.equalsIgnoreCase(XMLParser.ITEM) && currentMessage != null){
messages.add(currentMessage);
} else if (name.equalsIgnoreCase(XMLParser.CHANNEL)){
done = true;
}
break;
}
eventType = parser.next();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
String xml = writeXml();
List titles = new ArrayList(messages.size());
for (Message msg : messages){
titles.add(msg.getTitle());
}
ArrayAdapter adapter = new ArrayAdapter(this, R.layout.row,titles);
this.setListAdapter(adapter);
}
private void loadAndroidSAXFeed(){
AndroidSaxFeedParser parser = new AndroidSaxFeedParser();
long start = System.currentTimeMillis();
messages = parser.parse(is);
long duration = System.currentTimeMillis() - start;
String xml = writeXml();
List titles = new ArrayList(messages.size());
for (Message msg : messages){
titles.add(msg.getTitle());
}
ArrayAdapter adapter = new ArrayAdapter(this, R.layout.row,titles);
this.setListAdapter(adapter);
}
private void loadDOMFeed(){
DomFeedParser parser = new DomFeedParser();
long start = System.currentTimeMillis();
messages = parser.parse(is);
long duration = System.currentTimeMillis() - start;
String xml = writeXml();
List titles = new ArrayList(messages.size());
for (Message msg : messages){
titles.add(msg.getTitle());
}
ArrayAdapter adapter = new ArrayAdapter(this, R.layout.row,titles);
this.setListAdapter(adapter);
}
private void loadXMLPullFeed(){
XmlPullFeedParser parser = new XmlPullFeedParser();
long start = System.currentTimeMillis();
messages = parser.parse(is);
long duration = System.currentTimeMillis() - start;
String xml = writeXml();
List titles = new ArrayList(messages.size());
for (Message msg : messages){
titles.add(msg.getTitle());
}
ArrayAdapter adapter =
new ArrayAdapter(this, R.layout.row,titles);
this.setListAdapter(adapter);
}
private void loadSAXFeed(){
try{
long start = System.currentTimeMillis();
SaxFeedParser parser = new SaxFeedParser();
messages = parser.parse(is);
long duration = System.currentTimeMillis() - start;
String xml = writeXml();
List titles = new ArrayList(messages.size());
for (Message msg : messages){
titles.add(msg.getTitle());
}
ArrayAdapter adapter = new ArrayAdapter(this, R.layout.row,titles);
this.setListAdapter(adapter);
} catch (Throwable t){
}
}
private String writeXml(){
XmlSerializer serializer = Xml.newSerializer();
StringWriter writer = new StringWriter();
try {
serializer.setOutput(writer);
serializer.startDocument("UTF-8", true);
serializer.startTag("", "messages");
serializer.attribute("", "number", String.valueOf(messages.size()));
for (Message msg: messages){
serializer.startTag("", "message");
serializer.attribute("", "date", msg.getDate());
serializer.startTag("", "title");
serializer.text(msg.getTitle());
serializer.endTag("", "title");
serializer.startTag("", "url");
serializer.text(msg.getLink().toExternalForm());
serializer.endTag("", "url");
serializer.startTag("", "body");
serializer.text(msg.getDescription());
serializer.endTag("", "body");
serializer.endTag("", "message");
}
serializer.endTag("", "messages");
serializer.endDocument();
return writer.toString();
} catch (Exception e) {
throw new RuntimeException(e);
}
}}
Message.java
package samsung.parsers.xml;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;public class Message {
static SimpleDateFormat FORMATTER = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z");
private String title;
private URL link;
private String description;
private Date date; public String getTitle() {
return title;
} public void setTitle(String title) {
this.title = title.trim();
}
public URL getLink() {
return link;
}
public void setLink(String link) {
try {
this.link = new URL(link);
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
} public String getDescription() {
return description;
} public void setDescription(String description) {
this.description = description.trim();
} public String getDate() {
return FORMATTER.format(this.date);
} public void setDate(String date) {
while (!date.endsWith("00")){
date += "0";
}
try {
this.date = FORMATTER.parse(date.trim());
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
public Message copy(){
Message copy = new Message();
copy.title = title;
copy.link = link;
copy.description = description;
copy.date = date;
return copy;
}
}
RssHandler.java
package samsung.parsers.xml;
import java.util.ArrayList;
import java.util.List;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class RssHandler extends DefaultHandler{
private List messages;
private Message currentMessage;
private StringBuilder builder;
public List getMessages(){
return this.messages;
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
super.characters(ch, start, length);
builder.append(ch, start, length);
}
@Override
public void endElement(String uri, String localName, String name) throws SAXException {
super.endElement(uri, localName, name);
if (this.currentMessage != null){
if (localName.equalsIgnoreCase(XMLParser.TITLE)){
currentMessage.setTitle(builder.toString());
} else if (localName.equalsIgnoreCase(XMLParser.LINK)){
currentMessage.setLink(builder.toString());
} else if (localName.equalsIgnoreCase(XMLParser.DESCRIPTION)){
currentMessage.setDescription(builder.toString());
} else if (localName.equalsIgnoreCase(XMLParser.PUB_DATE)){
currentMessage.setDate(builder.toString());
} else if (localName.equalsIgnoreCase(XMLParser.ITEM)){
messages.add(currentMessage);
}
builder.setLength(0);
}
}
@Override
public void startDocument() throws SAXException {
super.startDocument();
messages = new ArrayList();
builder = new StringBuilder();
}
@Override
public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException {
super.startElement(uri, localName, name, attributes);
if (localName.equalsIgnoreCase(XMLParser.ITEM)){
this.currentMessage = new Message();
}
}
}
SaxFeedParser.java
package samsung.parsers.xml;
import java.io.InputStream;
import java.util.List;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
public class SaxFeedParser {
public SaxFeedParser(){
}
public List parse(InputStream is) {
SAXParserFactory factory = SAXParserFactory.newInstance();
try {
SAXParser parser = factory.newSAXParser();
RssHandler handler = new RssHandler();
parser.parse(is, handler);
return handler.getMessages();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
AndroidSaxFeedParser.java
package samsung.parsers.xml;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import android.sax.Element;
import android.sax.EndElementListener;
import android.sax.EndTextElementListener;
import android.sax.RootElement;
import android.util.Xml;
public class AndroidSaxFeedParser{
public AndroidSaxFeedParser() {
}
public List parse(InputStream is) {
final Message currentMessage = new Message();
RootElement root = new RootElement(XMLParser.RSS);
final List messages = new ArrayList();
Element channel = root.getChild(XMLParser.CHANNEL);
Element item = channel.getChild(XMLParser.ITEM);
item.setEndElementListener(new EndElementListener(){
@Override
public void end() {
messages.add(currentMessage.copy());
}
});
item.getChild(XMLParser.TITLE).setEndTextElementListener(new EndTextElementListener(){
@Override
public void end(String body) {
currentMessage.setTitle(body);
}
});
item.getChild(XMLParser.LINK).setEndTextElementListener(new EndTextElementListener(){
@Override
public void end(String body) {
currentMessage.setLink(body);
}
});
item.getChild(XMLParser.DESCRIPTION).setEndTextElementListener(new EndTextElementListener(){
@Override
public void end(String body) {
currentMessage.setDescription(body);
}
});
item.getChild(XMLParser.PUB_DATE).setEndTextElementListener(new EndTextElementListener(){
@Override
public void end(String body) {
currentMessage.setDate(body);
}
});
try {
Xml.parse(is, Xml.Encoding.UTF_8, root.getContentHandler());
} catch (Exception e) {
throw new RuntimeException(e);
}
return messages;
}
}
DomFeedParser.java
package samsung.parsers.xml;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class DomFeedParser {
public DomFeedParser() {
}
public List parse(InputStream is) {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
List messages = new ArrayList();
try {
DocumentBuilder builder = factory.newDocumentBuilder();
Document dom = builder.parse(is);
Element root = dom.getDocumentElement();
NodeList items = root.getElementsByTagName(XMLParser.ITEM);
for (int i=0;i<items.getLength();i++){
Message message = new Message();
Node item = items.item(i);
NodeList properties = item.getChildNodes();
for (int j=0;j<properties.getLength();j++){
Node property = properties.item(j);
String name = property.getNodeName();
if (name.equalsIgnoreCase(XMLParser.TITLE)){
message.setTitle(property.getFirstChild().getNodeValue());
} else if (name.equalsIgnoreCase(XMLParser.LINK)){
message.setLink(property.getFirstChild().getNodeValue());
} else if (name.equalsIgnoreCase(XMLParser.DESCRIPTION)){
StringBuilder text = new StringBuilder();
NodeList chars = property.getChildNodes();
for (int k=0;k<chars.getLength();k++){
text.append(chars.item(k).getNodeValue());
}
message.setDescription(text.toString());
} else if (name.equalsIgnoreCase(XMLParser.PUB_DATE)){
message.setDate(property.getFirstChild().getNodeValue());
}
}
messages.add(message);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
return messages;
}
}
XmlPullFeedParser.java
package samsung.parsers.xml;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import org.xmlpull.v1.XmlPullParser;
import android.util.Log;
import android.util.Xml;
public class XmlPullFeedParser {
public XmlPullFeedParser() {
}
public List parse(InputStream is) {
List messages = null;
XmlPullParser parser = Xml.newPullParser();
try {
parser.setInput(is, null);
int eventType = parser.getEventType();
Message currentMessage = null;
boolean done = false;
while (eventType != XmlPullParser.END_DOCUMENT && !done){
String name = null;
switch (eventType){
case XmlPullParser.START_DOCUMENT:
messages = new ArrayList();
break;
case XmlPullParser.START_TAG:
name = parser.getName();
if (name.equalsIgnoreCase(XMLParser.ITEM)){
currentMessage = new Message();
} else if (currentMessage != null){
if (name.equalsIgnoreCase(XMLParser.LINK)){
currentMessage.setLink(parser.nextText());
} else if (name.equalsIgnoreCase(XMLParser.DESCRIPTION)){
currentMessage.setDescription(parser.nextText());
} else if (name.equalsIgnoreCase(XMLParser.PUB_DATE)){
currentMessage.setDate(parser.nextText());
} else if (name.equalsIgnoreCase(XMLParser.TITLE)){
currentMessage.setTitle(parser.nextText());
}
}
break;
case XmlPullParser.END_TAG:
name = parser.getName();
if (name.equalsIgnoreCase(XMLParser.ITEM) && currentMessage != null){
messages.add(currentMessage);
} else if (name.equalsIgnoreCase(XMLParser.CHANNEL)){
done = true;
}
break;
}
eventType = parser.next();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
return messages;
}
}