這篇文章不是徹底原創,XML解析的部分參考了 liuhe688 的文章。文章地址:http://blog.csdn.net/liuhe688/article/details/6415593html
這是一個幾乎完整的過程。覆蓋面也比較廣。應用了AsyncTask, BaseAdapter, ListView, Dom, Sax, Pull等,這些也是開發應用中必不可少的部分。java
效果圖:node
首先,作了些準備工做。down了一份xml數據放在本地服務器上android
定義了一個model。apache
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; } }
一、客戶端發起請求,服務器
這是經過AsyncTask異步發起的請求。網絡
AsyncTask 主要須要複寫四個方法:app
onProExecute():這個方法會在UI線程中調用 execute(..)以後當即執行,在開發中一般作一些初始化和加載UI顯示的工做。dom
doInBackground(String... params):比較費時的操做,能夠放在這裏。網絡請求等...
onProgressUpdate(Integer... values):一般,咱們在耗時操做時候,好比download,會有一個百分比進度。在doInBackground()方法中調用
publishProgress()方法後,系統會調用此方法,更新進度信息。
onPostExecute(InputStream result):執行完畢之後調用的方法。
二、服務器端返回xml數據,
三、客戶端解析數據,最終呈現出來
我用了三種解析方法,參照上述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>