Android上經常使用xml來傳遞和交換數據。SAX(Simple API for XML)作為一種解析速度快並且占用內存少的xml解析器,非常適合Android等移動設備。SAX解析采用事件驅動,會判斷當前讀取到的字符是否符合xml語法中的某部分,從而觸發相應事件。xml中的節點分為2種類型,分別是Element Node(元素節點)和Text Node(文本節點)。對於元素節點,當讀取到開始標簽時會觸發startElement事件,當讀取到結束標簽時會觸發endElement事件。對於文本節點,當讀取到文本時會觸發characters事件。另外,xml文檔開始和結束時會分別觸發startDocument和endDocument事件。所謂事件其實就是一些回調方法,這些方法定義在ContentHandler接口中,用SAX解析一個xml文件主要也就是要根據xml文件的節點等信息編寫一個實現ContentHandler接口的實現類。
以下會用SAX解析這個test.xml文件,並用AndroidTextCase測試結果是否正確。
text.xml文件內容如下:
<?xml version="1.0" encoding="UTF-8"?>
<persons>
<person id="23">
<name>liming</name>
<age>30</age>
</person>
<person id="20">
<name>lixiang</name>
<age>25</age>
</person>
</persons>
過程如下:
在Eclipse下新建一個Android項目xml01
新建text.xml文件,放在src目錄下面
新建一個JavaBean:Person,屬性有id、name、age
編寫一個業務類:SAXPersonService,解析test.xml文件,這裡重點是根據test.xml文件中的節點名稱等信息編寫SAXParserHandler這個內部類,代碼如下:
package com.study.service;
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.study.bean.Person;
/**
* 使用SAX解析text.xml文件
* @author Administrator
*
*/
public class SAXPersonService {
public List<Person> getPersons(InputStream inputStream) throws Throwable{
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
SAXParserHandler handler = new SAXParserHandler();
parser.parse(inputStream, handler);
return handler.getPersons();
}
private final class SAXParserHandler extends DefaultHandler{
private List<Person> persons;
// 記錄正在訪問的文本節點的前一個節點名稱
private String tag;
private Person person;
public List<Person> getPersons() {
return persons;
}
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
if(tag != null){
if("name".equals(tag)){
// 根據文本節點取值設置name
person.setName(new String(ch, start, length));
}else if("age".equals(tag)){
// 根據文本節點取值設置age
person.setAge(Integer.parseInt(new String(ch, start, length)));
}
}
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
// localName是不帶命名空間前綴的標簽名
if("person".equals(localName)){
// 將person對象加入到集合中
persons.add(person);
// person對象設置為null
person = null;
}
// 節點結束時一定要將tag設置為null
// 否則會將空白字符賦值給name和age,從而出錯
tag = null;
}
@Override
public void startDocument() throws SAXException {
persons = new ArrayList<Person>();
}
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
// localName是不帶命名空間前綴的標簽名
if("person".equals(localName)){
person = new Person();
// 通過索引查找屬性的值
person.setId(Integer.parseInt(attributes.getValue(0)));
}
tag = localName;
}
}
}
在AndroidManifest.xml加入Android測試所需要的組件
<uses-library android:name="android.test.runner" />
以及
<instrumentation android:name="android.test.InstrumentationTestRunner"
android:targetPackage="com.study.action" android:label="Tests for My App" />
編寫一個AndroidTestCase:SAXPersonServiceTest,測試代碼如下:
package com.study.action;
import java.io.InputStream;
import java.util.List;
import android.test.AndroidTestCase;
import android.util.Log;
import com.study.bean.Person;
import com.study.service.SAXPersonService;
public class SAXPersonServiceTest extends AndroidTestCase {
private static final String TAG = "SAXPersonServiceTest";
public void testGetPersons() throws Throwable{
SAXPersonService personService = new SAXPersonService();
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("test.xml");
List<Person> persons = personService.getPersons(inputStream);
for(Person person : persons){
Log.i(TAG, person.getId() + ", " + person.getName() + ", " + person.getAge());
}
}
}
輸入日志,運行結果如下:
作者“新的啟程”