Android之XML檔案解析
轉載請註明出處:http://blog.csdn.net/joker_ya/article/details/38778971
OK!今天給帶來的是Android對XML檔案的解析方法。對於XML檔案,有三種解析方法。它們分別是:SAX解析,DOM解析和PULL解析。下面我們就一個一個的來分析。
1.SAX解析
含義:SAX(simple API for XML)是一種XML解析的替代方法。相比於DOM,SAX是一種速度更快,更有效的方法。它逐行掃描文件,一邊掃描一邊解析。而且相比於DOM,SAX可以在解析文件的任意時刻停止解析,但任何事物都有其相反的一面,對於SAX來說就是操作複雜。
原理:SAX,它既是一個介面,也是一個軟體包.但作為介面,SAX是事件驅動型XML解析的一個標準介面不會改變 SAX的工作原理簡單地說就是對文件進行順序掃描,當掃描到文件(document)開始與結束、元素(element)開始與結束、文件(document)結束等地方時通知事件處理函式,由事件處理函式做相應動作,然後繼續同樣的掃描,直至文件結束。
大多數SAX都會產生以下型別的事件:
1).在文件的開始和結束時觸發文件處理事件。
2).在文件內每一XML元素接受解析的前後觸發元素事件。
3).任何後設資料通常由單獨的事件處理
4).在處理文件的DTD或Schema時產生DTD或Schema事件。
5).產生錯誤事件用來通知主機應用程式解析錯誤。
2.DOM解析
DOM(Document Object Model)是一種用於XML 文件的物件模型,可用於直接訪問XML文件的各個部分。文件都被組織成了資料結構上的樹的形式,DOM解析以後可以將這個文件讀到記憶體中並且以樹的形式被組織。DOM比SAX更容易掌握,因為它沒有涉及回撥和複雜的狀態管理。然而,DOM的實現常常將所有XML節點保持在記憶體中,這使處理較大的文件變得效率低下。尤其是對於小記憶體的手機而言。
通過DOM將XML文件作為一個樹形結構,這種樹形結構也被稱為節點樹,如下圖所示。
3.PULL解析
PULL解析器的執行方式與SAX解析器相似。它提供了類似的事件,如開始元素和結束元素事件。使用parser.next()可以進入下一個元素並觸發相應的事件。事件將作為數值程式碼被髮送,因此可以使用一個switch對感興趣的事件進行選擇,然後進行相應的處理。當元素開始解析時,呼叫parser.nextText()方法可以獲取下一個Text型別元素的值。
和SAX不同的是,SAX的事件驅動是回撥相應的方法,我們需要提供回撥的方法,而後在SAX內部自動呼叫相應的方法。而PULL解析器並沒有強制要求我們提供觸發的方法。因為觸發的事件並不是一個方法,而是一個數字。至於觸發的事件要不要處理,就由程式設計師自己決定了。
好了,說了那麼多了,都是一些含義、原理什麼的。怪難理解的!那麼,接下來就寫一個Demo來幫助大家理解吧!
開啟工程新建名為AnalysisXMLDemo的專案,目錄結構如下:
首先給出我們要解析的XML檔案persons.xml
<span style="font-size:18px;"><span style="font-size:18px;"><?xml version="1.0" encoding="utf-8"?>
<persons>
<person id="1">
<name>張三</name>
<age>20</age>
</person>
<person id="2">
<name>李四</name>
<age>21</age>
</person>
<person id="3">
<name>王五</name>
<age>22</age>
</person>
<person id="4">
<name>麻六</name>
<age>23</age>
</person>
</persons></span></span>
然後我們新建一個Person.java類來接收解析的資料
<span style="font-size:18px;"><span style="font-size:18px;">package com.example.domain;
/**
* 建立一個Person類
* @author Joker_Ya
*
*/
public class Person {
private int id;
private String name;
private short age;
/**
* 建構函式
*/
public Person() {
}
public Person(String name, short age) {
this.name = name;
this.age = age;
}
public Person(int id, String name, short age) {
this.id = id;
this.name = name;
this.age = age;
}
/**
* 變數的set和get方法
*/
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 short getAge() {
return age;
}
public void setAge(short age) {
this.age = age;
}
/**
* toString方法
* @return
*/
@Override
public String toString() {
return "Person [id=" + id + ", name=" + name + ", age=" + age + "]";
}
}
</span></span>
接下來就是編寫SAX,DOM和PULL三種解析方法的解析程式碼了:
首先是SAX解析的程式碼SAXforHandler.java:
<span style="font-size:18px;"><span style="font-size:18px;">package com.example.analysisutils;
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 android.util.Log;
import com.example.domain.Person;
/**
* 新建SAXforHandler繼承DefaultHandler,
* 而DefaultHandler是實現了ContenHandler的介面,提供了相應的事件方法
*
* @author Joker_Ya
*
*/
public class SAXforHandler extends DefaultHandler {
private static final String TAG = "SAXforHandler";
private List<Person> persons;
private String perTag;// 記錄前一個標籤的名稱
private Person person;// 記錄當前Person
public List<Person> getPersons() {
return persons;
}
/**
* 對傳入的InputStream流進行SAX解析並返回結果
*
* @param inStream
* InputStream流
* @return 返回解析到的Person的list列表
* @throws Exception
* 丟擲異常
*/
public static List<Person> sax_XML(InputStream inStream) throws Exception {
SAXforHandler handler = new SAXforHandler();
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
parser.parse(inStream, handler);
List<Person> list = handler.getPersons();
inStream.close();
return list;
}
/**
* 通知應用程式文件的開始 適合在此事件中觸發初始化行為,
*/
@Override
public void startDocument() throws SAXException {
// TODO Auto-generated method stub
persons = new ArrayList<Person>();
// Log.v(TAG, "***startDocument()***");
}
/**
* 通知應用程式元素的開始,屬性作為Attributes引數傳遞
*
* @param uri
* 名稱空間
* @param localName
* 標籤名稱
* @param qName
* 帶名稱空間的標籤名
* @param attributes
* 存放該標籤的所有屬性
*/
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
// TODO Auto-generated method stub
if ("person".equals(localName)) {
for (int i = 0; i < attributes.getLength(); i++) {
// Log.v(TAG,
// "attributeName:"+attributes.getLocalName(i)+"_attributeValue:"+attributes.getValue(i));
person = new Person();
person.setId(Integer.valueOf(attributes.getValue(i)));
}
}
perTag = localName;
// Log.v(TAG, qName+"***startElement()***");
}
/**
* 當語法分析器在元素中發現文字(已經解析過的字元資料)時,characters()會被應用程式觸發
*
* @param ch
* 當前讀取到的TextNode位元組陣列
* @param start
* 位元組開始的位置
* @param length
* 當前TextNode的長度
*/
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
// TODO Auto-generated method stub
String data = new String(ch, start, length).trim();
if (!"".equals(data.trim())) {
Log.v(TAG, "content:" + data.trim());
}
if ("name".equals(perTag)) {
person.setName(data);
} else if ("age".equals(perTag)) {
person.setAge(new Short(data));
}
}
/**
* 通知應用程式元素的結束。
*/
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
// TODO Auto-generated method stub
// Log.v(TAG, qName+"***endElement()***");
if ("person".equals(localName) && person != null) {
persons.add(person);
person = null;
}
perTag = null;
}
/**
* 通知應用程式文件的結束
*/
@Override
public void endDocument() throws SAXException {
// TODO Auto-generated method stub
// Log.v(TAG, "***endDocument()***");
}
}
</span></span>
然後是DOM解析的程式碼DomService.java:
<span style="font-size:18px;"><span style="font-size:18px;">package com.example.analysisutils;
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.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import com.example.domain.Person;
/**
* DOM解析核心程式碼
* @author Joker_Ya
* 整個解析過程我們可以參照上文中的節點樹圖,獲得各個節點的順序是嚴格按照樹狀結構的。
*/
public class DomService {
public static List<Person> readXml(InputStream inStream) throws Exception {
List<Person> persons = new ArrayList<Person>();
//建立DocumentBuilderFactory,該物件將建立DocumentBuilder
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
//建立DocumentBuilder,DocumentBuilder將實際進行解析以建立Document物件
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(inStream);
Element root = document.getDocumentElement();
NodeList nodes = root.getElementsByTagName("person");
for (int i = 0; i < nodes.getLength(); i++) {
Element personElement = (Element) nodes.item(i);
Person person = new Person();
person.setId(Integer.parseInt((personElement.getAttribute("id"))));
NodeList childNodes = personElement.getChildNodes();
for (int y = 0; y < childNodes.getLength(); y++) {
Node childNode = childNodes.item(y);
if (childNode.getNodeType() == Node.ELEMENT_NODE) {
Element childElement = (Element) childNode;
if ("name".equals(childElement.getNodeName())) {
person.setName(childElement.getFirstChild()
.getNodeValue());
} else if ("age".equals(childElement.getNodeName())) {
person.setAge(new Short(childElement.getFirstChild()
.getNodeValue()));
}
}
}
persons.add(person);
}
return persons;
}
}
</span></span>
最後是PULL解析的程式碼PullService.java
<span style="font-size:18px;"><span style="font-size:18px;">package com.example.analysisutils;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import org.xmlpull.v1.XmlPullParser;
import android.util.Xml;
import com.example.domain.Person;
/**
* PULL解析核心程式碼
* @author Joker_Ya
*
*/
public class PullService {
public static List<Person> readXml(InputStream inStream) throws Exception {
List<Person> persons = null;
XmlPullParser parser = Xml.newPullParser();
parser.setInput(inStream, "UTF-8");
//得到PULL解析器的事件,其返回值是int型別的
int eventCode = parser.getEventType();
Person person = null;
// 用switch迴圈,如果獲得的事件碼是文件結束,那麼結束解析(parser.next()來觸發下一事件)
while (eventCode != XmlPullParser.END_DOCUMENT) {
switch (eventCode) {
case XmlPullParser.START_DOCUMENT:// 文件開始事件
persons = new ArrayList<Person>();
break;
case XmlPullParser.START_TAG:// 開始元素
// 判斷當前元素是否是需要檢索的元素
if ("person".equals(parser.getName())) {
person = new Person();
person.setId(Integer.parseInt(parser.getAttributeValue(0)));
} else if (person != null) {
if ("name".equals(parser.getName())) {
person.setName(parser.nextText());
} else if ("age".equals(parser.getName())) {
person.setAge(new Short(parser.nextText()));
}
}
break;
case XmlPullParser.END_TAG:// 結束元素
if ("person".equals(parser.getName()) && person != null) {
persons.add(person);
person = null;
}
break;
default:
break;
}
//下一個事件,是parser中最重要的方法
eventCode = parser.next();
}
return persons;
}
}
</span></span>
至此關於SAX解析,DOM解析和PULL解析的核心程式碼全部給出來了。其實弄懂了它們的原理和解析時的順序就很容易了。
下面就是介面activity_main.xml:
<span style="font-size:18px;"><span style="font-size:18px;"><RelativeLayout 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"
tools:context=".MainActivity" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
>
<Button
android:id="@+id/sax_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="SAX解析XML"
/>
<Button
android:id="@+id/dom_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="DOM解析XML"
/>
<Button
android:id="@+id/pull_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="PULL解析XML"
/>
<TextView
android:id="@+id/showtext"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<ListView
android:id="@+id/listview"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
></ListView>
</LinearLayout>
</RelativeLayout></span></span>
接下來就是MainActivity.java:
<span style="font-size:18px;"><span style="font-size:18px;">package com.example.analysisxmldemo;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.example.analysisutils.DomService;
import com.example.analysisutils.PullService;
import com.example.analysisutils.SAXforHandler;
import com.example.domain.Person;
import android.os.Bundle;
import android.app.Activity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView;
/**
*
* @author Joker_Ya
*
*/
public class MainActivity extends Activity implements OnClickListener {
private Button sax_button;
private Button dom_button;
private Button pull_button;
private TextView showtext;
private ListView listView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sax_button = (Button) findViewById(R.id.sax_button);
dom_button = (Button) findViewById(R.id.dom_button);
pull_button = (Button) findViewById(R.id.pull_button);
showtext = (TextView) findViewById(R.id.showtext);
listView = (ListView) findViewById(R.id.listview);
sax_button.setOnClickListener(this);
dom_button.setOnClickListener(this);
pull_button.setOnClickListener(this);
}
/**
* 按鈕的點選事件判斷和處理。
*/
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch (v.getId()) {
case R.id.sax_button://點選了“SAX解析XML”按鈕
try {
// 用類裝載器得到persons.xml檔案的輸入流
InputStream is = MainActivity.class.getClassLoader()
.getResourceAsStream("persons.xml");
List<Person> persons;
persons = SAXforHandler.sax_XML(is);
List<Map<String, String>> lists = new ArrayList<Map<String, String>>();
Map<String, String> hasmap;
String[] Strpersons = new String[persons.size()];
for (int i = 0; i < persons.size(); i++) {
hasmap = new HashMap<String, String>();
hasmap.put("number", Strpersons[i] = persons.get(i)
.toString() + "by SAX");
lists.add(hasmap);
}
showtext.setText("使用SAX解析persons.xml");
//新建一個SimpleAdapter介面卡
SimpleAdapter adapter = new SimpleAdapter(this, lists,
android.R.layout.simple_list_item_1,
new String[] { "number" },
new int[] { android.R.id.text1 });
//將解析的資料在listView中顯示
listView.setAdapter(adapter);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
case R.id.dom_button://點選了“DOM解析XML”按鈕
try {
InputStream is = MainActivity.class.getClassLoader()
.getResourceAsStream("persons.xml");
List<Person> persons;
persons = DomService.readXml(is);
String[] Strpersons = new String[persons.size()];
for (int i = 0; i < persons.size(); i++) {
Strpersons[i] = persons.get(i).toString() + "by DOM";
}
showtext.setText("使用DOM解析persons.xml");
//新建一個ArrayAdapter介面卡
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, Strpersons);
listView.setAdapter(adapter);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
case R.id.pull_button://點選了“PULL解析XML”按鈕
try {
InputStream is = MainActivity.class.getClassLoader()
.getResourceAsStream("persons.xml");
List<Person> persons;
persons = PullService.readXml(is);
String[] Strpersons = new String[persons.size()];
for (int i = 0; i < persons.size(); i++) {
Strpersons[i] = persons.get(i).toString() + "by PULL";
}
showtext.setText("使用PULL解析persons.xml");
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, Strpersons);
listView.setAdapter(adapter);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
default:
break;
}
}
}
</span></span>
在這裡要說明一點,就是使用SAX解析得到返回的資料並用ListView顯示時。如果用ArrayAdapter介面卡來繫結資料時,程式會報錯。因此SAX解析那裡使用了SimpleAdapter介面卡來繫結資料。至於為什麼會報錯,個人覺得是介面卡的問題,如果有哪位大神知道的麻煩告訴我一下。感謝。
最後的最後就是給出結果圖了:
首先是程式初始執行圖:
點選SAX解析XML按鈕圖:
點選DOM解析XML按鈕圖:
點選PULL解析XML按鈕圖:
噢,還有最後,那就是原始碼下載地址
相關文章
- jdom解析xml檔案XML
- GData解析XML檔案XML
- jquery 解析xml檔案jQueryXML
- android下解析.plist配置檔案的xml解析器AndroidXML
- 關於Android中xml佈局檔案之android 入門xml佈局檔案AndroidXML
- 使用 Java 解析XML檔案JavaXML
- 利用Perl解析XML檔案XML
- C#解析XML檔案C#XML
- python XML 檔案解析PythonXML
- Android學習之Build.xml檔案AndroidUIXML
- XML 檔案解析實踐 (DOM 解析)XML
- mybatis原始碼配置檔案解析之五:解析mappers標籤(解析XML對映檔案)MyBatis原始碼APPXML
- 讀取xml檔案 解析雙層xmlXML
- Android學習筆記之AndroidManifest.xml檔案解析(詳解)Android筆記XML
- Python解析XML檔案生成HTMLPythonXMLHTML
- Java XML檔案解析書目錄JavaXML
- python 解析xml 檔案: SAX方式PythonXML
- python 解析xml 檔案: DOM 方式PythonXML
- Python解析xml大檔案(sax)PythonXML
- AndroidManifest.xml檔案解析AndroidXML
- 使用PHP DOM-XML建立和解析XML檔案 (轉)PHPXML
- 如何使用 ABAP 程式碼解析 XML 檔案XML
- c#(解析xml檔案基礎方法)C#XML
- 基於 DOM 的 XML 檔案解析類XML
- jQuery解析xml檔案程式碼例項jQueryXML
- js載入解析xml檔案程式碼JSXML
- jQuery對xml檔案的解析例項jQueryXML
- python 解析xml 檔案: Element Tree 方式PythonXML
- Android中解析XMLAndroidXML
- 死磕Spring之IoC篇 - BeanDefinition 的解析階段(XML 檔案)SpringBeanXML
- 死磕Spring之IoC篇 - 解析自定義標籤(XML 檔案)SpringXML
- android解析plist檔案Android
- android: AAC檔案解析Android
- xml解析之domXML
- android 入門xml佈局檔案AndroidXML
- springMVC---配置檔案解析(web.xml)SpringMVCWebXML
- Java DOM4J 方式解析XML檔案JavaXML
- PHP-四種解析XML檔案的方法PHPXML