SAX解析XML檔案主要通過一個類DefaultHandler來實作,在這個類中重寫四個方法;startDocument()、startElement(String uri, String localName, String qName,Attributes attributes)、characters(char[] ch, int start, int length)、endElement(String uri, String localName, String qName)。由上述四個方法可以看出,其解析過程是一個個元素解析下去的。
首先自定義一個XML檔案:Student.xml,注意是建立file而不是xml。
<?xml version="1.0" encoding="utf-8"?>
<students>
<student id="1">
<name>張三</name>
<sex>男</sex>
<age>18</age>
</student>
<student id="2">
<name>李四</name>
<sex>女</sex>
<age>19</age>
</student>
<student id="3">
<name>王五</name>
<sex>男</sex>
<age>20</age>
</student>
</students>
然後建立一個student類
package com.example.xml_sax_demo_1;
public class Student {
private int id;
private String name;
private String sex;
private int age;
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 String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
接下來是最重要一步,建立一個類繼承DefaultHandler
package com.example.xml_sax_demo_1;
import java.util.ArrayList;
import java.util.List;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import android.R.integer;
public class SAXForHandler extends DefaultHandler {
private List<Student> list; //将解析的資料放在一個List裡面
private Student student;
private String tagName; //存放元素名稱
public List<Student> getList() {
return list;
}
@Override
public void startDocument() throws SAXException {
list = new ArrayList<Student>(); //開始解析時執行個體化list
}
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
if (qName.equals("student")) { //每個元素都是一個element
student = new Student(); //例如上面xml檔案中的student、name、sex、age
// 擷取student節點上的id屬性值
student.setId(Integer.parseInt(attributes.getValue(0))); //屬性和文本有所不同
}
this.tagName = qName; //将元素名稱賦給标志,為下一步做準備
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
if (qName.equals("student")) { //如果是student說明我們解析完了一項資料
this.list.add(this.student);
}
this.tagName = null; //将标志置為null
}
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
if (this.tagName != null) { //如果tagName不為null,之前看過一篇文章,元素前的空白處也是會被解析的。
String date = new String(ch, start, length); //開始存放資料
if (this.tagName.equals("name")) {
this.student.setName(date);
} else if (this.tagName.equals("sex")) {
this.student.setSex(date);
} else if (this.tagName.equals("age")) {
this.student.setAge(Integer.parseInt(date));
}
}
}
}
以解析第一項資料為例:
<students>
<student id="1">
<name>張三</name>
<sex>男</sex>
<age>18</age>
</student>
整個流程是:startDocument:執行個體化list → startElement:元素名為student,将其屬性賦給student的字段id,tagName = student → endElement: tagName = null → startElement:tagName = name → characters:元素名為name,将資料賦給student相應字段 → endElement:tagName = null → ....... → endElement:tagName為student,将一項資料存放在list裡面。可以這樣了解:遇到<type>就是startElement,遇到</type>就是endElement。
最後在activity裡面通過一個Button來解析資料,其中用到幾個類。
package com.example.xml_sax_demo_1;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.SAXException;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserFactory;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.util.Xml;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
try {
readXML();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
private void readXML() throws Exception {
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser parser = spf.newSAXParser();
SAXForHandler parseXml = new SAXForHandler(); // 執行個體化解析類
InputStream stream = this.getClass().getClassLoader()
.getResourceAsStream("Student.xml"); // 獲得輸入流
parser.parse(stream, parseXml); // 兩個參數,一個是輸入流,一個是解析類對象。
List<Student> list = parseXml.getList();
for (Student student : list) {
System.out.println(student.getId() + " " + student.getName() + " "
+ student.getSex() + " " + student.getAge());
}
}
}
結果:
小結:注意xml檔案的解析過程,完全自己寫的demo一直會出現inputstream can not be null的錯誤,估計是XML寫得有問題~~