Android 采用PULL來解析XML
概述:
PULL解析器小巧輕便,解析速度快,簡單易用,非常適合在Android移動設備中使用,Android系統內部在解析各種XML時也是用PULL解析器,Android官方推薦開發者們使用Pull解析技術。Pull解析技術是第三方開發的開源技術,它同樣可以應用于JavaSE開發。
PULL 的工作原理:
XML pull提供了開始元素和結束元素。當某個元素開始時,可以調用parser.nextText從XML文檔中提取所有字符數據。當解析到一個文檔結束時,自動生成EndDocument事件。
常用的XML pull的接口和類:
XmlPullParser:該解析器是一個在org.xmlpull.v1中定義的解析功能的接口。
XmlSerializer:它是一個接口,定義了XML信息集的序列。
XmlPullParserFactory:這個類用于在XMPULL V1 API中創建XML Pull解析器。
XmlPullParserException:拋出單一的XML pull解析器相關的錯誤。
PULL解析器的運行方式和SAX類似,都是基于事件的模式。
不同的是,在PULL解析過程中返回的是數字,且我們需要自己獲取產生的事件然后做相應的操作,而不像SAX那樣由處理器觸發一種事件的方法,執行我們的代碼:
讀取到xml的聲明返回 START_DOCUMENT; 結束返回 END_DOCUMENT ; 開始標簽返回 START_TAG;
結束標簽返回 END_TAG; 文本返回 TEXT。
幾種解析技術的比較與總結:
對于Android的移動設備而言,因為設備的資源比較寶貴,內存是有限的,所以我們需要選擇適合的技術來解析XML,這樣有利于提高訪問的速度。
DOM在處理XML文件時,將XML文件解析成樹狀結構并放入內存中進行處理。當XML文件較小時,我們可以選DOM,因為它簡單、直觀。
SAX則是以事件作為解析XML文件的模式,它將XML文件轉化成一系列的事件,由不同的事件處理器來決定如何處理。XML文件較大時,選擇SAX技術是比較合理的。雖然代碼量有些大,但是它不需要將所有的XML文件加載到內存中。這樣對于有限的Android內存更有效,而且Android提供了一種傳統的SAX使用方法以及一個便捷的SAX包裝器。 使用Android.util.Xml類,從示例中可以看出,會比使用 SAX來得簡單。
XML pull解析并未像SAX解析那樣監聽元素的結束,而是在開始處完成了大部分處理。這有利于提早讀取XML文件,可以極大的減少解析時間,這種優化對于連接速度較漫的移動設備而言尤為重要。對于XML文檔較大但只需要文檔的一部分時,XML Pull解析器則是更為有效的方法。
開發實例:
在asset定義了books.xml文件,對于它,只要是一份格式良好的xml文檔即可,具體內容根據需要定義。
讀取XML:從定義好的books.xml文件解析并顯示出來;
寫入XML:將解析后的內容再寫入到本地,這里也保存為名字為books.xml的文件。
例如:books.xml定義如下形式:
<?xml version="1.0" encoding="utf-8"?> <books> <book> <id>1001</id> <name>Thinking In Java</name> <price>80.00</price> </book> <book> <id>1002</id> <name>Core Java</name> <price>90.00</price> </book> <book> <id>1003</id> <name>Hello, Andriod</name> <price>100.00</price> </book> </books>
完整代碼:
PULLParserActivity:
package com.xsjayz.xml; import java.io.FileOutputStream; import java.io.InputStream; import java.util.List; import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.TextView; /** * PULL解析器,這里只是簡單的定義了一個TextView顯示解析結果,兩個Button操作。 * * @since 2012-08-23 */ public class PULLParserActivity extends Activity { private static final String TAG = "XML"; private TextView textView = null; private Button readBtn = null; private Button writeBtn = null; private BookParser parser; private List<Book> booksList; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); textView = (TextView) findViewById(R.id.txt); readBtn = (Button) findViewById(R.id.read_btn); writeBtn = (Button) findViewById(R.id.write_btn); readBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { try { InputStream is = getAssets().open("books.xml"); parser = new PULLBookParser(); booksList = parser.parse(is); for (Book book : booksList) { Log.i(TAG, book.toString()); } for (Book book : booksList) { textView.setText(textView.getText() + book.toString()); } } catch (Exception e) { Log.e(TAG, e.getMessage()); } } }); writeBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { try { String xmlString = parser.serialize(booksList); // 序列化 FileOutputStream fos = openFileOutput("books.xml", Context.MODE_PRIVATE); fos.write(xmlString.getBytes("UTF-8")); } catch (Exception e) { Log.e(TAG, e.getMessage()); } } }); } }
PULLBookParser:
package com.xsjayz.xml; 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; /** * PULL解析器,實現了BookParser接口 */ public class PULLBookParser implements BookParser { /** * @param is * @return booksList */ @Override public List<Book> parse(InputStream is) throws Exception { List<Book> booksList = null; Book book = null; // 由android.util.Xml創建一個XmlPullParser實例 XmlPullParser parser = Xml.newPullParser(); // 設置輸入流 并指明編碼方式 parser.setInput(is, "UTF-8"); // 產生第一個事件 int eventType = parser.getEventType(); while (eventType != XmlPullParser.END_DOCUMENT) { switch (eventType) { // 判斷當前事件是否為文檔開始事件 case XmlPullParser.START_DOCUMENT: booksList = new ArrayList<Book>(); // 初始化books集合 break; // 判斷當前事件是否為標簽元素開始事件 case XmlPullParser.START_TAG: if (parser.getName().equals("book")) { // 判斷開始標簽元素是否是book book = new Book(); } else if (parser.getName().equals("id")) { eventType = parser.next(); // 得到book標簽的屬性值,并設置book的id book.setId(Integer.parseInt(parser.getText())); } else if (parser.getName().equals("name")) { // 判斷開始標簽元素是否是book eventType = parser.next(); book.setName(parser.getText()); } else if (parser.getName().equals("price")) { // 判斷開始標簽元素是否是price eventType = parser.next(); book.setPrice(Float.parseFloat(parser.getText())); } break; // 判斷當前事件是否為標簽元素結束事件 case XmlPullParser.END_TAG: if (parser.getName().equals("book")) { // 判斷結束標簽元素是否是book booksList.add(book); // 將book添加到books集合 book = null; } break; } // 進入下一個元素并觸發相應事件 eventType = parser.next(); } return booksList; } /** * @param books * @return writer.toString() */ @Override public String serialize(List<Book> books) throws Exception { // 由android.util.Xml創建一個XmlSerializer實例 XmlSerializer serializer = Xml.newSerializer(); StringWriter writer = new StringWriter(); // 設置輸出方向為writer serializer.setOutput(writer); serializer.startDocument("UTF-8", true); serializer.startTag("", "books"); for (Book book : books) { serializer.startTag("", "book"); serializer.attribute("", "id", 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(); return writer.toString(); } }
BookParser:
package com.xsjayz.xml; import java.io.InputStream; import java.util.List; public interface BookParser { /** * 解析輸入流 得到Book對象集合 * * @param is * @throws Exception */ public List<Book> parse(InputStream is) throws Exception; /** * 序列化Book對象集合 得到XML形式的字符串 * * @param books * @throws Exception */ public String serialize(List<Book> books) throws Exception; }
Book:
package com.xsjayz.xml; /** * Book的model類,定義了Book的所有狀態,訪問器和修改器,重寫了toString方法 */ 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; } @Override public String toString() { return "id:" + id + "\nname:" + name + "\nprice:" + price + "\n"; } }