-------------------------------------SAX解析xml----------------------------------
》Sax定義
SAX是一個解析速度快並且占用內存少的xml解析器,非常適合用於android等移動設備
SAX全稱是Simple API for Xml,既是指一種接口,也是一個軟件包
作為接口,sax是事件驅動型xml解析的一個標准接口
》Sax特點
1. 解析效率高,占用內存少
2.可以隨時停止解析
3.不能載入整個文檔到內存
4.不能寫入xml
5.SAX解析xml文件采用的是事件驅動
---sax並不需要解析完 整個文檔,在按內容順序解析文檔的過程中,sax會判斷當前讀到的字符是否合法xml語法中的某部分,如果符合就會觸發事件
》Sax工作原理
Sax的工作原理簡單的說,就是對文檔進行順序掃描,掃描到文檔(document)開始與結束,掃描到元素(element)開始、結束等地方時調用事件處理
處理函數做相應動作,然后繼續掃描,直到文檔結束。
》Sax解析文檔過程
1.繼承DefaultHandler ,並實現方法
2.創建SAX解析器工廠
3.獲得解析器
4.獲得輸入流
5.使用輸入流,和實現接口作參數,調用解析器的解析方法進行解析
》defaultHandler 接口是實現contentHandler接口
ContentHandler接口中的常用方法
>startDocument()
當遇到文檔開頭的時候,調用這個方法,可以在其中做一些與准備工作
>endDocument()
當文檔結束的時候,調用這個方法,可以在其中做一些善后工作
>startElement(String namespaceURL, String localName, String qName, Attributes atts)
當讀到一個開始標簽的時候,會觸發這個方法。namespaceURL就是命名空間,localName是不帶命名空間前綴的標簽名,
qName是待命名空間前綴的標簽名。通過atts可以得到所有的屬性名和相應的值。
>endElement(String uri, String localName, String name)
當遇到結束標簽的時候,調用這個方法
>characters(char[] ch, int start, int length)
這個方法用來處理在xml文件中讀到的內容,第一個參數為文件的字符串內容,后面兩個參數是讀到的字符串在這個數組中的起始位置和長度,
使用new String(ch, start, length)就可以獲取內容
》SAX解析實例
-------------1.在src下創建xml 文件,並結合成實體類Userinfo.java-------------
<?xml version="1.0" encoding="UTF-8"?>
<admins>
<admin id="1">
<name>阿龍</name>
<age>23</age>
<sex>男</sex>
<email>along@qq.com</email>
</admin>
</admins>
----------Userinfo.java----
String name;
int age;
String sex;
String email;
String id;
。。。 生成get、set方法
--------------------2.創建XmlPaser繼承defaultHandler----------------------
public class XmlPaser extends DefaultHandler{
//創建user對象為把查到的內容放到里面
Userinfo user;
public Userinfo getUser() {
return user;
}
public void setUser(Userinfo user) {
this.user = user;
}
//定義標簽變量
String tagName = null;
//開始文檔處理些准備工作
public void startDocument() throws SAXException {
user = new Userinfo();
super.startDocument();
}
//讀到第一個標簽觸發
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
tagName = localName;
if("admin".equals(tagName)){
user.setId(attributes.getValue(0));
System.out.println("id: "+attributes.getValue(0));
}
}
//讀取文本內容
public void characters(char[] ch, int start, int length)
throws SAXException {
if(tagName!=null){
if("name".equals(tagName)){
String str = new String(ch,start,length);
user.setName(str);
System.out.println("name: "+str);
}else if("age".equals(tagName)){
String str = new String(ch,start,length);
user.setAge(Integer.parseInt(str));
System.out.println("age: "+str);
}else if("sex".equals(tagName)){
String str = new String(ch,start,length);
user.setSex(str);
System.out.println("sex: "+str);
}else if("email".equals(tagName)){
String str = new String(ch,start,length);
user.setEmail(str);
System.out.println("email: "+str);
}
}
}
//遇到結束標簽
public void endElement(String uri, String localName, String qName)
throws SAXException {
tagName=null;
}
//文檔讀完
public void endDocument() throws SAXException {
super.endDocument();
}
}
----------------布局文件main省略-----------
----------------------3.-類SAXActivity繼承Activity----------------
Button btnOk;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
btnOk = (Button)this.findViewById(R.id.button1);
btnOk.setOnClickListener(new OnClickListener() {
public void onClick(View v){
//創建解析工廠和解析器
SAXParserFactory spf = SAXParserFactory.newInstance();
try{
SAXParser sp = spf.newSAXParser();
//解析
XmlPaser xp = new XmlPaser();
InputStream is = this.getClass().getClassLoader().getResourceAsStream("user.xml");
sp.parse(is,xp);
//獲得讀取到的內容
Userinfo user = xp.getUser();
//在頁面顯示
.................
}
}
});
}
---------------------------------------Dom解析Xml--------------------------------------------
》DOM簡介
dom全稱Document Object Model ,為xml文檔的已解析版本定義了一組接口。解析器讀入整個文檔,然后構建一個主流內存的樹結構,
然后代碼就可以使用dom接口來操作這個樹結構
》DOM的特點
>優點
1.整個文檔樹在內存中,便於操作;支持刪除、修改、重新排列等多種功能
2.通過樹形結構存取xml文檔
3.可以在樹的某個節點上向前或向后移動
>缺點
1.將整個文檔調入內存(包括無用的節點),浪費時間和空間
>適用場合
一旦解析了文檔還需多次訪問這些數據;硬件資源充足(內存,cpu)
》DOM解析步驟
1.創建解析器工廠
2.獲得解析器工廠
3.接受一個xml文檔作為輸入參數名,並得到一個xml的文檔對象(Document)
4.操作文檔對象
》解析實例:
-----------------------1.創建要解析的xml文件、和實體類(Person)---------------------------
<?xml version="1.0" encoding="utf-8"?>
<users>
<user id="1">
<name>Tom</name>
<age>19</age>
</user>
<user id="2">
<name>Jaary</name>
<age>18</age>
</user>
</users>
實體類 略
-----------------------2. Dom解析(DomService.java)-----------------------------------
public List<Person> getPersons(InputStream input) throws Throwable{
//獲得解析器工廠
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
//獲得解析器
DocumentBuilder builder = factory.newDocumentBuilder();
//進行解析
Document doc = builder.parse(input);
List<Person> personlist = new new ArrayList<Person>();
//獲得所有叫user的節點
NodeList list = doc.getElementsByTagName(user);
String id="";
String name="";
String age="";
for(int i=0;i<list.getLength();i++){
//取得第i個user節點
Element node=(Element)list.item(i);
Person p=new Person();
//獲取id屬性
id=node.getAttribute("id");
//獲得user節點下的子節點列表
NodeList userList=node.getChildNodes();
for(int j=0;j<userList.getLength();j++){
//判斷是否是元素節點,name和age屬於元素節點
if(userList.item(j).getNodeType()==Node.ELEMENT_NODE){
Element childNode=(Element)userList.item(j);
if("name".equals(childNode.getNodeName())){
name=childNode.getFirstChild().getNodeValue();
}
else if("age".equals(childNode.getNodeName())){
age=childNode.getFirstChild().getNodeValue();
}
p.setName(name);
p.setAge(age);
p.setId(Integer.parseInt(id));
}
}
personList.add(p);
}
return personList;
}
-------------------------3.Activity01繼承Activity類----------------------------------------------------
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
InputStream is=this.getClass().getClassLoader().getResourceAsStream("test.xml");
DomService dom=new DomService();
try {
List<Person> ps=dom.getPersons(is);
for(Person p:ps){
System.out.println(p.getId());
System.out.println(p.getName());
System.out.println(p.getAge());
}
} catch (Exception e) {
e.printStackTrace();
}
}
--------------------------------------pull解析-----------------------------
》pull解析器簡介
1.pull解析器是android內置的解析器,解析原理與sax類似
2.pull它提供了類似的事件。
如:開始元素和結束元素事件,使用parse.next()可以進入下一個元素並觸發相應的事件,事件將作為數值代碼被發送
因此可以使用一個switch對感興趣的事件進行處理。當元素開始解析時,調用parser.nextText()方法獲取下一個Text類型節點的值
》pull與sax的不同之處
1.pull讀取xml文件后觸發相應的事件調用方法返回的是數字。
2.pull可以在程序中控制,想解析到哪里就可以停止到哪里
3.Android中更推薦使用pull解析
》pull解析步驟
1.創建解析器對象
XmlPullParser paser = Xml.newPullParser();
2.進行解析
paser.setInput(input,"utf-8");
3.產生第一個解析事件
int eventType = paser.getEventType();
4.可以使用循環判斷是否繼續解析
while(eventType!=XmlPullParser.END_DOCUMENT){}
》解析實例
-------------------1。創建xml.及實例對象(Person.java)----------------略
--------------------2.pull解析(PullService .java)----------------------
List<Person> getAlPerson(InputStream is) throws XmlPullParserException, IOException{
List<Person> persons=null;
Person p=null;
XmlPullParser parser=Xml.newPullParser();
parser.setInput(is,"utf-8");
//獲得事件類型
int type=parser.getEventType();
while(type!=XmlPullParser.END_DOCUMENT){
switch(type){
case XmlPullParser.START_DOCUMENT://文檔開始
persons=new ArrayList<Person>();
break;
case XmlPullParser.START_TAG://元素開始
if(parser.getName().equals("user")){
p=new Person();
String id=parser.getAttributeValue(0);
p.setId(Integer.parseInt(id));
}
else if(parser.getName().equals("name")){
if(p!=null){
String name=parser.nextText();
p.setName(name);
}
}
else if(parser.getName().equals("age")){
String age=parser.nextText();
p.setAge(age);
}
break;
case XmlPullParser.END_TAG:
if("user".equals(parser.getName())){
persons.add(p);
p=null;
}
break;
}
type=parser.next();
}
return persons;
}
}
------------------------------------Activity類-----------------------------------
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
InputStream is=this.getClass().getClassLoader().getResourceAsStream("test.xml");
PullService pps=new PullService();
try {
List<Person> ps=pps.getPersons(is);
for(Person p:ps){
System.out.println(p.getId());
System.out.println(p.getName());
System.out.println(p.getAge());
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (XmlPullParserException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
SAX、DOM、PULL的比較
SAX、DOM、PULL各有自己的特點,具體操作XML的時候該如何選擇呢?
1.內存占用
這是一個根本性問題。由於Android手機性能相對於現在的應用操作還是有限的,程序對內存的占用直接影響到了解析XML的速度。在這點上,SAX、Pull以它們比DOM占用更少的內存的解析方式,更適合於Android手機開發。
2.編程方式
SAX采用事件驅動,在相應事件觸發的時候,會調用用戶編寫好的方法。也就是說,每解析一類XML,就要編寫一個新的適合該類XML的處理類。這顯然不是一個好的解決辦法,盡管其在解析速度上是那么優秀。而這點,DOM因為是W3C的規范。所以被更多程序員所知道和使用。所以在開發過程中,沒有太大困難。Pull雖然屬於一個小眾的,甚至是不為人知的解析器,但是通過上面對其介紹和示例,我們應該能看出它的簡潔性。
3.訪問與修改
由於采用的是流式解析,這就說明它們不能像DOM那樣隨機訪問,XML的其中任意一個節點。並且,SAX並沒有提供對文檔中加節點的API,更沒有刪除,修改文檔內容的方法。
4.訪問方式
這是產生它們解析快慢的根本原因。如果把SAX和Pull比喻成一目十行,很快但是是走馬觀花的閱讀方式的話,那么DOM就是逐字逐句的閱讀,很慢,但是是過目不忘。這里還要需要注意的是,SAX,Pull解析的方式是同步的,即解析器讀到哪里,就對哪里進行處理。而DOM是已經將文件解析好后,供用戶提取XML中感興趣的信息。
總結:
出於對內存占用的考慮,推薦使用SAX或者Pull來工作。可是根據它們工作的原理:如果只是需要XML最后的幾個節點的相關信息,或者出現反復檢索XML文件的情況。那么基本上三者在性能上就沒有什么差異,反而在這時,SAX的處理類會使程序顯得比其他的實現方式顯得臃腫。所以,想做一個高性能的Android軟件,還是要多分析,選擇合適的工具,才能發揮它的作用。