天天看點

Android開發必備武器,處理X“.NET研究”ML的利器——SAX快速上手

  相信各位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 {

上海企業網站設計與制作yle="color: #008080;"> 2

3 public void startElement(String uri, String localName, String qName,

4 }

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;

6 private String sn;

7 public String getName() {

8 return name;

9 }

10 public void setName(String name) {

11 this.name = name;

13 public 上海闵行企業網站制作/span>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  

     下面再來完成處理器的代碼:

2

3 private List<Student> studentList;

5 private boolean inStudent = false;

6

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>();

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();

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 上海網站建設pan style="color: #000000;"> 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

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文檔了:

5 List<Student> list;

9 list = myHandler.getStudentList();

     可以看到,解析完XML文檔之後,我們就可以用處理器重的getStudentList方法取得解析後的資料了。

     最後總結一下,SAX并不複雜,隻要了解了它的思維方式,我們就可以遊刃有餘,使它成為我們開發的利器,這篇文章向大家介紹了SAX的一些基本知識,希望能起到一個抛磚引玉的作用,大家能夠使用它來創造出更多好的應用,當然可能有一些地方解釋的還不是十分完美,如果有一些不好了解的地方,還望大家指出。

繼續閱讀