編輯:Android開發實例
相信各位android開發者,對SAX已經並不陌生了,SAX(Simple API for XML),是一個使用非常廣泛的XML解析標准,通常使用Handler模式來處理XML文檔,這種處理模式和我們平常習慣的理解方式很不同,身邊也經常有一些朋友在剛接觸SAX的時候會覺得理解起來有些困難。其實SAX並不復雜,只不過是換了一種思維方式,正如它的名字所表示的,為了讓我們以更簡單的方式來處理XML文檔,下面我們就開始吧。
我們通常的理解方式是,我們給出一個輸入(比如xml文檔的地址),然後程序返回給我們數據(比如解析後的xml文檔結構),我們在返回給我們的結果中進行相應的操作,而SAX以一種更簡單的方式來處理XML文檔的解析,也就是處理器模式,一個使用SAX的簡單示例:
1 SAXParserFactory spf = SAXParserFactory.newInstance();
2 SAXParser sp = spf.newSAXParser();
3 XMLReader reader = sp.getXMLReader();
4
5
6 reader.setContentHandler(myHandler);
7 reader.parse(new InputSource(new URL(url).openStream()));
正如上面的代碼,我們使用一系列工廠方法生成了一個XMLReader對象,隨後,最關鍵的一行就是reader.setContentHandler,這裡為這個reader設置了一個處理器,這個處理器的具體內容是要我們來完成的,稍後會詳細介紹,最後調用parse方法完成文檔的解析。這是SAX的一個基本流程。
下面我們來詳細介紹一下處理器,SAX處理器使用的是一種和我們平時的理解方式不太一樣的處理形式,是在遍歷文檔的同時,讓我們來進行文檔的處理。 用一個實際的例子來解釋更為方便,假如有下面這樣一個XML文檔:
1 <student>
2 <name>張三</name>
3 <age>22</age>
4 <sn>1001</sn>
5 </student>
6 <student>
7 <name>李四</name>
8 <age>21</age>
9 <sn>1002</sn>
10 </student>
使用SAX的時候,解析器會對XML文檔進行深度優先遍歷,在遍歷的時候,會根據條件調用處理器中的方法,如上面的XML文檔,首先會遍歷到第一個student的起始節點,這時我們可以在處理器中進行一些需要的處理,隨後會分別遍歷name,age,sn起始節點和結束節點,以此類推,這樣說起來可能還不夠直觀,下面我們就來看看一個處理器的基本結構:
1 public class MyHandler extends DefaultHandler {
2
3 public void startElement(String uri, String localName, String qName,
4 }
5
6 public void endElement(String uri, String localName, String qName)
7 throws SAXException {
8 }
9
10 public void characters(char[] ch, int start, int length)
11 throws SAXException {
12 }
13 }
如上面的代碼,這裡有幾個比較重要的方法,startElement是進入到起始節點的時候會調用的方法,例如上面的xml文件,進入到<student>節點時,就會調用startElement方法。 endElement方法,在結束一個節點的時候會調用,例如進入到</student>節點時,該方法會被調用。 characters方法,在進入XML節點的文本節點(TextNode)時會被調用,例如<name>張三</name>,在便利到‘張三’這個文本節點的時候,這個方法會被調用。
另外還有兩個回調方法,分別為startDocument,endDocument,顧名思義,這兩個方法為進入文檔和離開文檔時要調用的方法。
下面我們就來自己寫一個處理器來解析上面的XML文檔。首先我們需要將每個節點封裝成一個實體對象:
1 public class Student {
2 private String name;
3
4 private int age;
5
6 private String sn;
7 public String getName() {
8 return name;
9 }
10 public void setName(String name) {
11 this.name = name;
12 }
13 public int getAge() {
14 return age;
15 }
16 public void setAge(int age) {
17 this.age = age;
18 }
19 public String getSn() {
20 return sn;
21 }
22 public void setSn(String sn) {
23 this.sn = sn;
24 }
25
26
27 }
28
下面再來完成處理器的代碼:
1 public class MyHandler extends DefaultHandler {
2
3 private List<Student> studentList;
4
5 private boolean inStudent = false;
6
7 private boolean studentName = false;
8
9 private boolean studentAge = false;
10
11 private boolean studentSN = false;
12
13 private Student curStudent ;
14
15 public MyHandler() {
16
17 studentList = new ArrayList<Student>();
18 }
19 @Override
20 public void startElement(String uri, String localName, String qName,
21 Attributes attributes) throws SAXException {
22
23 String tagName = localName.length() != 0 ? localName : qName;
24 tagName = tagName.toLowerCase().trim();
25
26 if(tagName.equals("student")) {
27 inStudent = true;
28 curStudent = new Student();
29 }
30
31 if(inStudent) {
32
33 if(tagName.equals("name")) {
34 studentName = true;
35 }else if(tagName.equals("age")) {
36 studentAge = true;
37 }else if(tagName.equals("sn")) {
38 studentSN = true;
39 }
40 }
41
42 }
43
44 @Override
45 public void endElement(String uri, String localName, String qName)
46 throws SAXException {
47
48 String tagName = localName.length() != 0 ? localName : qName;
49 tagName = tagName.toLowerCase().trim();
50
51 if(tagName.equals("student")) {
52 inStudent = true;
53 studentList.add(curStudent);
54 }
55
56 if(inStudent) {
57
58 if(tagName.equals("name")) {
59 studentName = false;
60 }else if(tagName.equals("age")) {
61 studentAge = false;
62 }else if(tagName.equals("sn")) {
63 studentSN = false;
64 }
65 }
66 }
67
68 @Override
69 public void characters(char[] ch, int start, int length)
70 throws SAXException {
71
72 if(studentName) {
73 curStudent.setName(curStudent.getName() + new String(ch,start,length));
74 }else if (studentAge) {
75 curStudent.setAge(Integer.parseInt(new String(ch,start,length)));
76 }else if(studentSN) {
77 curStudent.setSn(curStudent.getSn() + new String(ch, start, length));
78 }
79 }
80 }
81
如上面的代碼,我們使用了一系列的布爾標志變量來保存文檔的遍歷狀態,先從startElement說起,當我們進入到student節點的時候,我們將inStudent狀態設置為true,表示我們已經處於student節點之中,同時創建了一個student對象,相應地,在endElement方法中,我們遇到student結束的時候,會把這個對象添加到我們的studentList中,並將inStudent狀態設置為false。同樣的,在startElement方法中判斷instudent狀態,如果當前已經處於student節點中,並且遍歷到name,age或者sn節點時,我們也將相應的標志設置為true。這樣在遍歷的文本節點的時候就可以在characters方法中通過判斷這些標志位來為Student對象設置相應的屬性。
注意到,這裡curStudent.setName(curStudent.getName() + new String(ch,start,length)),我們用以前的值和新的值連接起來,而不是直接設置curStudent.setName(new String(ch,start,length))。這是因為在遍歷<name>.....</name>這中間的文本節點的時候,有些時候這對標簽中的內容可能會被看做多個文本節點,比如包含Html實體的情況下 <name>張 三</name>,這裡相當於包含了兩個文本節點,如果不使用連接的方式而采用直接設置的方式,那麼我們最終只能得到最後一次設置的值,因為前面設置的被覆蓋了。那麼我們最終取得到的名字就是‘三’了。
這個處理器的核心分功能就算完成了,下面我們還需要增加一個方法,用來返回處理後的內容:
1 public List<Student> getStudentList() {
2 return studentList;
3 }
完成了處理器之後,我們就可以用剛開始介紹的方法來解析XML文檔了:
1 SAXParserFactory spf = SAXParserFactory.newInstance();
2 SAXParser sp = spf.newSAXParser();
3 XMLReader reader = sp.getXMLReader();
4
5 List<Student> list;
6 reader.setContentHandler(myHandler);
7 reader.parse(new InputSource(new URL(url).openStream()));
8
9 list = myHandler.getStudentList();
可以看到,解析完XML文檔之後,我們就可以用處理器重的getStudentList方法取得解析後的數據了。
最後總結一下,SAX並不復雜,只要理解了它的思維方式,我們就可以游刃有余,使它成為我們開發的利器,這篇文章向大家介紹了SAX的一些基本知識,希望能起到一個拋磚引玉的作用,大家能夠使用它來創造出更多好的應用,當然可能有一些地方解釋的還不是十分完美,如果有一些不好理解的地方,還望大家指出。:lol
另外下面是SAX的一個官方網站,裡面有一些介紹和代碼示例,英文不錯的童鞋可以來這裡參考一下:
http://www.saxproject.org
登錄應用程序的屏幕,詢問憑據登錄到一些特定的應用。可能需要登錄到Facebook,微博等本章介紹了,如何創建一個登錄界面,以及如何管理安全問題和錯誤嘗試。首先,必須定義兩
可以顯示在的Android任務,通過加載進度條的進展。進度條有兩種形狀。加載欄和加載微調(spinner)。在本章中,我們將討論微調(spinner)。Spinner 用
很多時候我們開發的軟件需要向用戶提供軟件參數設置功能,例如我們常用的QQ,用戶可以設置是否允許陌生人添加自己為好友。對於軟件配置參數的保存,如果是window軟件
當我們第一次下載QQ並且打開的時候,會有一個新手引導,引導是幾張圖片,再加上一些文字說明,向右滑動,直到結束,今天一大早起來研究了一下關於此種效果的實現之View