在現代技術中不論使用何種語言﹐解析XML文件資料已是很常見的方法﹐XML比起過去的INI格式更有彈性更能描述豐富的資料﹐且做為一種共同性的文件格式更能讓大家有同樣的規範遵詢﹐不會因為獨樹一格的格式使得使用技巧變得多樣而複雜。
在 Android 中解析XML的方式有三種DOM﹑SAX及PULL﹐這些使用的差異性在網路上已有多篇文章介紹﹐範例也有許多。然而凡事總要自己親自嘗試過才能知其中的奧妙。因此自己自訂了一個XML格式分別使用DOM及SAX方式來讀取做相同的事﹐親自感受當中有何不同。
XML檔(Books.xml)
01 | <? xml version = "1.0" encoding = "UTF-8" ?> |
03 | < book id = "P631" name = "Android 2.X 應用程式開發實戰" publishers = "碁峯" price = "580" > |
06 | < book id = "P697" name = "深入淺出 Android 遊戲程式開發範例大全" publishers = "博碩文化" price = "620" > |
10 | < book id = "XP6037" name = "Silverlight 4 商業級應用程式開發" publishers = "悅知文化" price = "590" > |
11 | < auther name = "Frank LaVigne. Cameron Albert" /> |
將Books.xml 這個檔案放在 src 之下﹐如下圖所示
主畫面 Layout(main.xml)
01 | <? xml version = "1.0" encoding = "utf-8" ?> |
03 | android:orientation = "vertical" |
04 | android:layout_width = "fill_parent" |
05 | android:layout_height = "fill_parent" |
08 | android:layout_width = "fill_parent" |
09 | android:layout_height = "wrap_content" |
10 | android:text = "讀取XML資料" /> |
11 | < Button android:layout_width = "wrap_content" |
12 | android:layout_height = "wrap_content" |
14 | android:id = "@+id/saxbtn" /> |
15 | < Button android:layout_width = "wrap_content" |
16 | android:layout_height = "wrap_content" |
17 | android:text = "使用DOM剖析" |
18 | android:id = "@+id/dombtn" /> |
主畫面很簡單就只有兩個Button﹐分別表示將使用SAX方式與DOM方式來解析XML資料檔。
接下來將分別使用SAX與DOM的方式讀取Books.xml然後以ListView元件呈現資料﹐而這裏要做的是用不同的技術分別呈現﹐使用的Layout都一樣﹐這裏會建立一個主要呈現的Layout檔booklist.xml
booklist.xml
01 | <? xml version = "1.0" encoding = "utf-8" ?> |
04 | android:layout_width = "match_parent" |
05 | android:layout_height = "match_parent" android:orientation = "vertical" > |
06 | < TextView android:id = "@+id/list_title" |
07 | android:layout_width = "wrap_content" |
08 | android:layout_height = "wrap_content" |
10 | android:layout_gravity = "center" /> |
11 | < ListView android:id = "@+id/bookListView" |
12 | android:layout_width = "fill_parent" |
13 | android:layout_height = "fill_parent" /> |
這個layout很簡單﹐只有一個TextView當Title﹐還有一個ListView﹐這個ListView就是要用來顯示解析Books.xml的資料。為了這個ListView﹐需要再建一個layout檔book_data.xml﹐這個book_data.xml用來表示在ListView中的每一筆資料呈現方式。
book_data.xml
01 | <? xml version = "1.0" encoding = "utf-8" ?> |
04 | android:layout_height = "match_parent" |
05 | android:orientation = "vertical" |
06 | android:layout_width = "fill_parent" > |
07 | < LinearLayout android:id = "@+id/linearLayout1" |
08 | android:orientation = "horizontal" |
09 | android:layout_height = "wrap_content" |
10 | android:layout_width = "fill_parent" > |
11 | < TextView android:text = "TextView" |
12 | android:layout_width = "wrap_content" |
13 | android:layout_height = "wrap_content" |
14 | android:id = "@+id/bookNameTxt" |
15 | android:textColor = "@color/yellow" /> |
17 | < LinearLayout android:id = "@+id/linearLayout2" |
18 | android:orientation = "horizontal" |
19 | android:layout_height = "wrap_content" |
20 | android:layout_width = "fill_parent" > |
21 | < TextView android:text = "TextView" |
22 | android:textColor = "@color/white" |
23 | android:gravity = "left" |
24 | android:id = "@+id/publishersTxt" |
25 | android:layout_width = "wrap_content" |
26 | android:layout_height = "wrap_content" ></ TextView > |
27 | < TextView android:text = "TextView" |
28 | android:textColor = "@color/green" |
29 | android:gravity = "right" |
30 | android:id = "@+id/priceTxt" |
31 | android:layout_height = "wrap_content" |
32 | android:layout_width = "match_parent" ></ TextView > |
Layout還是以圖形來看比較容易看得懂﹐在book_data.xml的排版中每一筆資料的呈現方式第一列為書名(黃色的TextView)﹐第二列則有出版社(白色的TextView)及價錢(綠色的TextView)。
根據 Books.xml的資料我們知道至少有id(書籍編號)﹑name(書名)﹑publishers(出版社)﹑price(價錢)...這些屬性值﹐而從我們想要顯示的資料來看至少也要有name(書名)﹑publishers(出版社)﹑price(價錢)這三個欄位﹐我們可以定義一個class檔(Book.java)來表示一本書籍的基本資料。
Book.java
package com.sample.AndroidUseXML; |
public String publishers; |
public Book(String id, String name, String publishers, String price){ |
this .publishers=publishers; |
public void setId(String id) { |
public String getName() { |
public void setName(String name) { |
public String getPublishers() { |
public void setPublishers(String publishers) { |
this .publishers = publishers; |
public String getPrice() { |
public void setPrice(String price) { |
在這個專案一開始create的Activity是UseXML﹐這裏就是單純的去觸發兩個button的動作而已。
UseXML.java
01 | package com.sample.AndroidUseXML; |
03 | import android.app.Activity; |
04 | import android.content.Intent; |
05 | import android.os.Bundle; |
06 | import android.view.View; |
07 | import android.widget.Button; |
09 | public class UseXML extends Activity { |
15 | public void onCreate(Bundle savedInstanceState) { |
16 | super .onCreate(savedInstanceState); |
17 | setContentView(R.layout.main); |
23 | private void findView(){ |
24 | saxbtn=(Button)findViewById(R.id.saxbtn); |
25 | dombtn=(Button)findViewById(R.id.dombtn); |
28 | private void setListener(){ |
29 | saxbtn.setOnClickListener(saxbtnls); |
30 | dombtn.setOnClickListener(dombtnls); |
33 | private Button.OnClickListener saxbtnls= new Button.OnClickListener(){ |
35 | public void onClick(View arg0) { |
36 | Intent intent= new Intent(); |
37 | intent.setClass(UseXML. this , UseSaxParse. class ); |
40 | Bundle bundle = new Bundle(); |
42 | bundle.putString( "list_title" , list_title); |
43 | intent.putExtras(bundle); |
45 | startActivity(intent); |
49 | private Button.OnClickListener dombtnls= new Button.OnClickListener(){ |
51 | public void onClick(View v) { |
52 | Intent intent= new Intent(); |
53 | intent.setClass(UseXML. this , UseDomParse. class ); |
56 | Bundle bundle = new Bundle(); |
58 | bundle.putString( "list_title" , list_title); |
59 | intent.putExtras(bundle); |
61 | startActivity(intent); |
DOM篇
由UseXML中第53行﹐我們知道要使用DOM的方式我們呼叫了UseDomParse的Activity
UseDomParse.java
01 | package com.sample.AndroidUseXML; |
03 | import java.io.InputStream; |
04 | import java.util.ArrayList; |
07 | import android.app.Activity; |
08 | import android.os.Bundle; |
09 | import android.util.Log; |
10 | import android.widget.ListView; |
11 | import android.widget.TextView; |
13 | public class UseDomParse extends Activity { |
14 | String TAG= "UseDomParse" ; |
19 | protected void onCreate(Bundle savedInstanceState) { |
20 | super .onCreate(savedInstanceState); |
21 | setContentView(R.layout.booklist); |
27 | private void findView(){ |
28 | list_title=(TextView)findViewById(R.id.list_title); |
29 | bookList=(ListView)findViewById(R.id.bookListView); |
32 | private void ShowXMLData(){ |
33 | Bundle bundle= this .getIntent().getExtras(); |
34 | list_title.setText( "書籍列表(" +bundle.getString( "list_title" )+ ")" ); |
36 | List<Book> books= new ArrayList<Book>(); |
39 | bookList.setAdapter( new BookAdapter( this ,books)); |
42 | private List<Book> getXMLData() { |
43 | List<Book> books = new ArrayList<Book>(); |
45 | InputStream inStream = UseDomParse. class .getClassLoader() |
46 | .getResourceAsStream( "Books.xml" ); |
51 | books = DomParseXML.ReadBookXML(inStream); |
52 | } catch (Exception er) { |
53 | Log.e(TAG, er.getMessage()); |
第21行指明了要用booklist.xml的layout。
第32行的ShowXMLData()是用來顯示資料。
第37行的books=getXMLData();是用來取得以DOM解析資料後得到的List物件。
第39行的bookList這一個ListView將使用自定的DataAdapter做為資料來源。
第45行的位置是讀取檔案﹐因為檔案是直接放在src之下。如果檔案是放在com.sample.AndroidUseXML之下﹐那麼就必須加上路徑﹐如48行。
在第48行books = DomParseXML.ReadBookXML(inStream); 這裏是我們主要用DOM去解析方法。
DomParseXML.java
01 | package com.sample.AndroidUseXML; |
03 | import java.io.InputStream; |
04 | import java.util.ArrayList; |
07 | import javax.xml.parsers.DocumentBuilder; |
08 | import javax.xml.parsers.DocumentBuilderFactory; |
10 | import org.w3c.dom.Document; |
11 | import org.w3c.dom.Element; |
12 | import org.w3c.dom.NodeList; |
17 | *InputStream可以是網路也可以是文件 |
19 | public class DomParseXML { |
20 | public static List<Book> ReadBookXML(InputStream inStream) throws Exception{ |
21 | List<Book> books= new ArrayList<Book>(); |
22 | DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance(); |
23 | DocumentBuilder builder=factory.newDocumentBuilder(); |
24 | Document document=builder.parse(inStream); |
25 | Element root=document.getDocumentElement(); |
26 | NodeList nodes=root.getElementsByTagName( "book" ); |
28 | for ( int i= 0 ;i<nodes.getLength();i++){ |
29 | Element bookElement=(Element)nodes.item(i); |
31 | book.setId(bookElement.getAttribute( "id" )); |
32 | book.setName(bookElement.getAttribute( "name" )); |
33 | book.setPublishers(bookElement.getAttribute( "publishers" )); |
34 | book.setPrice(bookElement.getAttribute( "price" )); |
BookAdapter.java
01 | package com.sample.AndroidUseXML; |
05 | import android.content.Context; |
06 | import android.view.LayoutInflater; |
07 | import android.view.View; |
08 | import android.view.ViewGroup; |
09 | import android.widget.BaseAdapter; |
10 | import android.widget.TextView; |
12 | public class BookAdapter extends BaseAdapter { |
13 | private LayoutInflater inflater; |
14 | List<Book> books= null ; |
16 | public BookAdapter(Context context,List<Book> books){ |
17 | inflater=LayoutInflater.from(context); |
22 | public int getCount() { |
27 | public Object getItem( int arg0) { |
32 | public long getItemId( int arg0) { |
37 | public View getView( int arg0, View arg1, ViewGroup arg2) { |
38 | ViewHolder viewHolder; |
40 | arg1=inflater.inflate(R.layout.book_data, null ); |
41 | viewHolder= new ViewHolder(); |
42 | viewHolder.bookNameTxt=(TextView)arg1.findViewById(R.id.bookNameTxt); |
43 | viewHolder.publishersTxt=(TextView)arg1.findViewById(R.id.publishersTxt); |
44 | viewHolder.priceTxt=(TextView)arg1.findViewById(R.id.priceTxt); |
45 | arg1.setTag(viewHolder); |
47 | viewHolder=(ViewHolder)arg1.getTag(); |
56 | viewHolder.bookNameTxt.setText(books.get(arg0).name); |
57 | viewHolder.publishersTxt.setText(books.get(arg0).publishers); |
58 | viewHolder.priceTxt.setText( "NT." +books.get(arg0).price+ " 元" ); |
63 | private class ViewHolder{ |
65 | TextView publishersTxt; |
SAX篇
以DOM的方式﹐可以看得出寫的程式並不多﹐如果改以SAX就不大一樣了。
由UseXML中第37行﹐我們知道要使用SAX的方式我們呼叫了UseSaxParse的Activity。
UseSaxParse.java
01 | package com.sample.AndroidUseXML; |
03 | import java.io.InputStream; |
04 | import java.util.ArrayList; |
07 | import android.app.Activity; |
08 | import android.os.Bundle; |
09 | import android.util.Log; |
10 | import android.widget.ListView; |
11 | import android.widget.TextView; |
13 | public class UseSaxParse extends Activity { |
19 | protected void onCreate(Bundle savedInstanceState) { |
20 | super .onCreate(savedInstanceState); |
21 | setContentView(R.layout.booklist); |
27 | private void findView(){ |
28 | list_title=(TextView)findViewById(R.id.list_title); |
29 | bookList=(ListView)findViewById(R.id.bookListView); |
32 | private void ShowXMLData(){ |
33 | Bundle bundle= this .getIntent().getExtras(); |
34 | list_title.setText( "書籍列表(" +bundle.getString( "list_title" )+ ")" ); |
36 | List<Book> books= new ArrayList<Book>(); |
39 | bookList.setAdapter( new BookAdapter( this ,books)); |
42 | private List<Book> getXMLData(){ |
43 | List<Book> books= new ArrayList<Book>(); |
45 | InputStream inStream=UseSaxParse. class .getClassLoader().getResourceAsStream( "Books.xml" ); |
46 | books = SAXParseXML.readXML(inStream); |
48 | Log.e(TAG, er.getMessage()); |
第46行的SAXParseXML
SAXParseXML.java
01 | package com.sample.AndroidUseXML; |
03 | import java.io.InputStream; |
06 | import javax.xml.parsers.SAXParser; |
07 | import javax.xml.parsers.SAXParserFactory; |
09 | public class SAXParseXML { |
10 | public static List<Book> readXML(InputStream inStream) throws Exception{ |
11 | SAXParserFactory factory=SAXParserFactory.newInstance(); |
12 | SAXParser saxParse=factory.newSAXParser(); |
14 | SAXContentHandler handler= new SAXContentHandler(); |
15 | saxParse.parse(inStream, handler); |
18 | return handler.getBooks(); |
第14行的SAXContentHandler是關鍵﹐必須建立一個class繼承自DefaultHandler﹐並且在這當中去實作以下以個方法
startDocument()
characters(char[] ch, int start, int length)
startElement(String uri, String localName, String qName, Attributes attributes)
public void endElement(String uri, String localName, String qName)
SAXContentHandler.java
01 | package com.sample.AndroidUseXML; |
03 | import java.util.ArrayList; |
06 | import org.xml.sax.Attributes; |
07 | import org.xml.sax.SAXException; |
08 | import org.xml.sax.helpers.DefaultHandler; |
10 | public class SAXContentHandler extends DefaultHandler { |
11 | private List<Book> books; |
13 | private String preTag; |
15 | public List<Book> getBooks(){ |
23 | public void startDocument() throws SAXException { |
24 | books = new ArrayList<Book>(); |
31 | public void characters( char [] ch, int start, int length) |
40 | public void startElement(String uri, String localName, String qName, |
41 | Attributes attributes) throws SAXException { |
42 | if ( "book" .equals(localName)){ |
44 | book.setId(attributes.getValue( "" , "id" )); |
45 | book.setName(attributes.getValue( "" , "name" )); |
46 | book.setPublishers(attributes.getValue( "publishers" )); |
47 | book.setPrice(attributes.getValue( "price" )); |
56 | public void endElement(String uri, String localName, String qName) |
58 | if ( "book" .equals(localName) && book!= null ){ |
實際的執行結果
相关文档:
http://blog.csdn.net/haha_mingg/article/details/6329694
http://www.cnblogs.com/zhangdongzi/archive/2011/04/14/2016434.html
http://www.cnblogs.com/khldragon/archive/2011/11/08/1968283.html