这篇文章不是完全原创,XML解析的部分参考了 liuhe688 的文章。文章地址:http://blog.csdn.net/liuhe688/article/details/6415593
这是一个几乎完整的过程。覆盖面也比较广。应用了AsyncTask, BaseAdapter, ListView, Dom, Sax, Pull等,这些也是开发应用中必不可少的部分。
效果图:
首先,做了些准备工作。down了一份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>