Android 通过Dom, Sax, Pull解析网络xml数据

时间:2024-11-04 12:03:44

这篇文章不是完全原创,XML解析的部分参考了 liuhe688 的文章。文章地址:http://blog.****.net/liuhe688/article/details/6415593

这是一个几乎完整的过程。覆盖面也比较广。应用了AsyncTask, BaseAdapter, ListView, Dom, Sax, Pull等,这些也是开发应用中必不可少的部分。

效果图:

Android 通过Dom, Sax, Pull解析网络xml数据  Android 通过Dom, Sax, Pull解析网络xml数据  Android 通过Dom, Sax, Pull解析网络xml数据

首先,做了些准备工作。down了一份xml数据放在本地服务器上

Android 通过Dom, Sax, Pull解析网络xml数据

定义了一个model。

book.java

package com.example.phonedemo.model;

public class Book {
private int id;
private String name;
private float price; public int getId() {
return id;
} public void setId(int id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public float getPrice() {
return price;
} public void setPrice(float price) {
this.price = price;
} }

1、客户端发起请求,

这是通过AsyncTask异步发起的请求。

AsyncTask 主要需要复写四个方法:

onProExecute():这个方法会在UI线程中调用 execute(..)之后立即执行,在开发中通常做一些初始化和加载UI显示的工作。

doInBackground(String... params):比较费时的操作,可以放在这里。网络请求等...

onProgressUpdate(Integer... values):通常,我们在耗时操作时候,比如download,会有一个百分比进度。在doInBackground()方法中调用

publishProgress()方法后,系统会调用此方法,更新进度信息。

onPostExecute(InputStream result):执行完毕以后调用的方法。

2、服务器端返回xml数据,

3、客户端解析数据,最终呈现出来

我用了三种解析方法,参照上述blog的地址。不过,在他得代码中稍有问题。ID是没有的。我在我的代码中改正了。

三种方式都是解析一个xml,所以写了一个接口文件。

BookParserImpl.java

package com.example.phonedemo.util;

import java.io.InputStream;
import java.util.List; import com.example.phonedemo.model.Book; public interface BookParserImpl {
public List<Book> parse(InputStream is); public String serialize(List<Book> books);
}

然后,三种解析分别实现它即可。

Dom解析方式

优点:功能齐全,强大。缺点:因为需要完全加载文档,导致,比较耗资源。前辈说j2ee中用的较多。

我虽然也学Java,但是一直都与前台打交道。曾经学的东西,工作中不用,就全忘了。罪过,罪过...

 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parser(InputStream input);

上述dom初始化解析实例的代码。

DomBookParser.java

package com.example.phonedemo.util;

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.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList; import com.example.phonedemo.model.Book; public class DomBookParser implements BookParserImpl { @Override
public List<Book> parse(InputStream is) {
List<Book> list = new ArrayList<Book>();
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = null;
Document doc = null;
try {
builder = factory.newDocumentBuilder();
doc = builder.parse(is);
NodeList itemList = doc.getDocumentElement().getElementsByTagName(
"book");
for (int i = 0; i < itemList.getLength(); i++) {
Book book = new Book();
Node node = itemList.item(i);
NodeList child = node.getChildNodes();
NamedNodeMap attr = node.getAttributes();
book.setId(Integer.parseInt(attr.getNamedItem("id")
.getNodeValue()));
for (int j = 0; j < child.getLength(); j++) {
Node childItem = child.item(j);
String nodeName = childItem.getNodeName();
if (nodeName.equals("name")) {
book.setName(childItem.getFirstChild().getNodeValue());
} else if (nodeName.equals("price")) {
book.setPrice(Float.parseFloat(childItem
.getFirstChild().getNodeValue()));
}
} list.add(book);
} } catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return list;
} @Override
public String serialize(List<Book> books) {
// TODO Auto-generated method stub
return null;
}
}

Sax解析方式

sax是事件驱动型的,比起dom来更加灵巧。也更加简单快速。

SaxBookParser.java

package com.example.phonedemo.util;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List; import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory; import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler; import com.example.phonedemo.model.Book; public class SaxBookParser implements BookParserImpl { @Override
public List<Book> parse(InputStream is) {
// TODO Auto-generated method stub
SAXParserFactory factory = SAXParserFactory.newInstance();
MyHandler handler = null;
try {
SAXParser parser = factory.newSAXParser();
handler = new MyHandler();
parser.parse(is, handler);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return handler.getBooks();
} /**
* <b>解析xml的辅助类</b><br />
* <b>startDocument()</b> 当遇到文档的开头的时候,调用这个方法,可以在其中做一些预处理的工作。<br />
* <b>endDocument()</b> 和上面的方法相对应,当文档结束的时候,调用这个方法,可以在其中做一些善后的工作。 <br/>
* <b>startElement(String namespaceURI, String localName, String qName,
* Attributes atts)</b>当读到一个开始标签的时候,会触发这个方法。<br />
* <b>endElement(String uri, String localName, String name)</b>
* 这个方法和上面的方法相对应,在遇到结束标签的时候,调用这个方法。<br />
* <b>characters(char[] ch, int start, int length)</b>
* 这个方法用来处理在XML文件中读到的内容,第一个参数用于存放文件的内容,<br />
* 后面两个参数是读到的字符串在这个数组中的起始位置和长度,使用new String(ch,start,length)就可以获取内容。
*
* @author qxj
*
*/
class MyHandler extends DefaultHandler { private List<Book> books;
private Book book;
private StringBuilder builder; public List<Book> getBooks() {
return books;
} /**
* 接收元素中字符数据的通知。
*
* @param ch
* - 字符。
* @param start
* - 字符数组中的开始位置。
* @param length
* - 从字符数组中使用的字符数。
*/
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
// TODO Auto-generated method stub
super.characters(ch, start, length);
builder.append(ch, start, length);
} /**
* 接收元素结束的通知
*
* @param uri
* - 名称空间 URI,如果元素没有任何名称空间 URI,或者没有正在执行名称空间处理,则为空字符串。
* @param localName
* - 本地名称(不带前缀),如果没有正在执行名称空间处理,则为空字符串。
* @param qName
* - 限定的名称(带有前缀),如果限定的名称不可用,则为空字符串。
* @exception SAXException
* - 任何 SAX 异常,可能包装另外的异常。
*/
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
// TODO Auto-generated method stub
super.endElement(uri, localName, qName);
if (localName.equals("book")) {
books.add(book);
} else if (localName.equals("name")) {
book.setName(builder.toString());
} else if (localName.equals("price")) {
book.setPrice(Float.parseFloat(builder.toString()));
}
} /**
* 接收文档的开始的通知
*
* @exception - SAXException - 任何 SAX 异常,可能包装另外的异常
*/
@Override
public void startDocument() throws SAXException {
// TODO Auto-generated method stub
super.startDocument();
books = new ArrayList<Book>();
builder = new StringBuilder();
} /**
* 接收元素开始的通知。
*
* @param uri
* - 名称空间 URI,如果元素没有任何名称空间 URI,或者没有正在执行名称空间处理,则为空字符串。
* @param localName
* - 本地名称(不带前缀),如果没有正在执行名称空间处理,则为空字符串。
* @param qName
* - 限定的名称(带有前缀),如果限定的名称不可用,则为空字符串。
* @param attributes
* - 附加到元素的属性。如果没有属性,则它将是空的 Attributes 对象。
* @exception SAXException
* - 任何 SAX 异常,可能包装另外的异常
*/
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
// TODO Auto-generated method stub
super.startElement(uri, localName, qName, attributes);
if (localName.equals("book")) {
book = new Book();
if (attributes != null) {
book.setId(Integer.parseInt(attributes.getValue("id")));
}
}
builder.setLength(0);
} } @Override
public String serialize(List<Book> books) {
// TODO Auto-generated method stub
return null;
} }

Pull解析方式

我最喜欢这种解析方式,它最轻巧,简便。android 用到了很多xml的文件,系统都是用pull来解析的。从这个层面中可以看出来。android建议使用这种解析方式。

PullBookParser.java

package com.example.phonedemo.util;

import java.io.InputStream;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List; import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlSerializer; import android.util.Xml; import com.example.phonedemo.model.Book; public class PullBookParser implements BookParserImpl { @Override
public List<Book> parse(InputStream is) {
// TODO Auto-generated method stub
List<Book> books = null;
Book book = null; XmlPullParser parser = Xml.newPullParser();
try {
parser.setInput(is, "UTF-8");
int eventType = parser.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
switch (eventType) {
case XmlPullParser.START_DOCUMENT:
books = new ArrayList<Book>();
break;
case XmlPullParser.START_TAG:
if (parser.getName().equals("book")) {
book = new Book();
book.setId(Integer.parseInt(parser.getAttributeValue(0)));
} else if (parser.getName().equals("name")) {
parser.next();
book.setName(parser.getText());
} else if (parser.getName().equals("price")) {
parser.next();
book.setPrice(Float.parseFloat(parser.getText()));
}
break;
case XmlPullParser.END_TAG:
if (parser.getName().endsWith("book")) {
books.add(book);
book = null;
}
break;
}
parser.next();
eventType = parser.getEventType();
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return books;
} @Override
public String serialize(List<Book> books) {
// TODO Auto-generated method stub
XmlSerializer serializer = Xml.newSerializer();
StringWriter writer = new StringWriter();
try {
serializer.setOutput(writer);
serializer.startDocument("UTF-8", true);
serializer.startTag("", "books");
for (Book book : books) {
serializer.startTag("", "book");
serializer.attribute("", "id", String.valueOf(book.getId())); serializer.startTag("", "name");
serializer.text(book.getName());
serializer.endTag("", "name"); serializer.startTag("", "price");
serializer.text(book.getPrice() + "");
serializer.endTag("", "price");
serializer.endTag("", "book");
}
serializer.endTag("", "books");
serializer.endDocument();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("doc: " + writer.toString());
return writer.toString();
}
}

最后,附上Activity

package com.example.phonedemo;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List; import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient; import android.app.Activity;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast; import com.example.phonedemo.model.Book;
import com.example.phonedemo.util.DomBookParser;
import com.example.phonedemo.util.PullBookParser;
import com.example.phonedemo.util.SaxBookParser; public class XMLParserDemo extends Activity { private static final String TAG = "XMLParserDemo"; private static final String PATH = "http://192.168.1.121:8080/wwwroot/android/book.html"; private List<Book> list = null;
private Button dom = null;
private Button sax = null;
private Button pull = null;
private Button clear = null;
private TextView parser = null;
private ListView listView = null; /**
* 异步请求数据
*
* @author qinxijuan
*
*/
private class MyAsyncTask extends AsyncTask<String, Integer, InputStream> { // 表示当前使用哪一种解析方式,0:dom ; 1: sax; 2:pull
private int flag = 0; public MyAsyncTask(int flag) {
this.flag = flag;
} @Override
protected void onPostExecute(InputStream result) {
if (result != null) {
if (flag == 0) {
domParserFromInputStream(result);
} else if (flag == 1) {
saxParserFromInputStream(result);
} else if (flag == 2) {
pullParserFromInputStream(result);
}
} else {
Toast.makeText(XMLParserDemo.this, "数据获取失败!",
Toast.LENGTH_SHORT).show();
}
} @Override
protected void onPreExecute() {
Log.i(TAG, "onPreExecute() Loading ... ");
} @Override
protected void onProgressUpdate(Integer... values) {
// TODO Auto-generated method stub
super.onProgressUpdate(values);
} @Override
protected InputStream doInBackground(String... params) { InputStream result = null;
HttpClient client = new DefaultHttpClient();
HttpGet get = new HttpGet(params[0]);
HttpResponse response = null;
try {
response = client.execute(get);
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
HttpEntity entity = response.getEntity();
result = entity.getContent();
}
} catch (Exception e) {
e.printStackTrace();
} return result;
} } static class ViewHolder {
TextView id;
TextView name;
TextView price;
} class MyBaseAdapter extends BaseAdapter { private List<Book> list = null;
private LayoutInflater ly = null; public MyBaseAdapter(Context context, List<Book> list) {
this.ly = LayoutInflater.from(context);
this.list = list;
} @Override
public int getCount() {
// TODO Auto-generated method stub
return this.list.size();
} @Override
public Object getItem(int arg0) {
// TODO Auto-generated method stub
return null;
} @Override
public long getItemId(int arg0) {
// TODO Auto-generated method stub
return 0;
} @Override
public View getView(int position, View convertView, ViewGroup arg2) {
ViewHolder viewHolder = null;
if (convertView == null) {
viewHolder = new ViewHolder();
convertView = ly.inflate(R.layout.simpleitem, null);
viewHolder.id = (TextView) convertView.findViewById(R.id.id);
viewHolder.name = (TextView) convertView
.findViewById(R.id.name);
viewHolder.price = (TextView) convertView
.findViewById(R.id.age);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.id.setText(String.valueOf(list.get(position).getId()));
viewHolder.name.setText(list.get(position).getName());
viewHolder.price.setText(String.valueOf(list.get(position)
.getPrice()));
return convertView;
} } @Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
super.setContentView(R.layout.xml_parser_layout); this.dom = (Button) super.findViewById(R.id.dom);
this.sax = (Button) super.findViewById(R.id.sax);
this.pull = (Button) super.findViewById(R.id.pull);
this.clear = (Button) super.findViewById(R.id.clear);
this.parser = (TextView) super.findViewById(R.id.parser);
this.listView = (ListView) super.findViewById(R.id.list_view); this.clear.setOnClickListener(new OnClickListener() { @Override
public void onClick(View v) {
// TODO Auto-generated method stub
list = new ArrayList<Book>();
MyBaseAdapter adapter = new MyBaseAdapter(XMLParserDemo.this,
list);
listView.setAdapter(adapter);
parser.setText("数据清除完毕");
}
}); this.dom.setOnClickListener(new OnClickListener() { @Override
public void onClick(View v) {
// TODO Auto-generated method stub
MyAsyncTask mTask = new MyAsyncTask(0);
mTask.execute(PATH);
parser.setText("使用dom方式解析");
}
}); this.sax.setOnClickListener(new OnClickListener() { @Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
MyAsyncTask mTask = new MyAsyncTask(1);
mTask.execute(PATH);
parser.setText("使用sax方式解析");
}
}); this.pull.setOnClickListener(new OnClickListener() { @Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
MyAsyncTask mTask = new MyAsyncTask(2);
mTask.execute(PATH);
parser.setText("使用pull方式解析");
}
});
} public void domParserFromInputStream(InputStream input) {
list = new ArrayList<Book>();
DomBookParser domParser = new DomBookParser();
System.out.println("input: " + input.toString());
list = domParser.parse(input);
MyBaseAdapter adapter = new MyBaseAdapter(this, list);
this.listView.setAdapter(adapter);
} public void saxParserFromInputStream(InputStream input) {
list = new ArrayList<Book>();
SaxBookParser saxParser = new SaxBookParser();
list = saxParser.parse(input);
MyBaseAdapter adapter = new MyBaseAdapter(this, list);
this.listView.setAdapter(adapter);
} public void pullParserFromInputStream(InputStream input) {
PullBookParser pullParser = new PullBookParser();
list = pullParser.parse(input);
MyBaseAdapter adapter = new MyBaseAdapter(this, list);
this.listView.setAdapter(adapter);
} }

xml_parser_layout.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" > <LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" > <Button
android:id="@+id/dom"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Dom" /> <Button
android:id="@+id/sax"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Sax" /> <Button
android:id="@+id/pull"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="pull" /> <Button
android:id="@+id/clear"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="clear" />
</LinearLayout> <LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content" > <TextView
android:id="@+id/parser"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text=" " />
</LinearLayout> <LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content" > <ListView
android:id="@+id/list_view"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
</ListView>
</LinearLayout> </LinearLayout>