Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發 >> 開發入門 >> Android開發必備武器,處理XML的利器--SAX快速上手

Android開發必備武器,處理XML的利器--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. reader.setContentHandler(myHandler);
  5. 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. public void startElement(String uri, String localName, String qName,
  3. }

  4. public void endElement(String uri, String localName, String qName)
  5. throws SAXException {
  6. }

  7. public void characters(char[] ch, int start, int length)
  8. throws SAXException {
  9. }
  10. }


如上面的代碼,這裡有幾個比較重要的方法,startElement是進入到起始節點的時候會調用的方法,例如上面的XML文件,進入到<student>節點時,就會調用startElement方法。
endElement方法,在結束一個節點的時候會調用,例如進入到</student>節點時,該方法會被調用。
characters方法,在進入XML節點的文本節點(TextNode)時會被調用,例如<name>張三</name>,在便利到‘張三’這個文本節點的時候,這個方法會被調用。

另外還有兩個回調方法,分別為startDocument,endDocument,顧名思義,這兩個方法為進入文檔和離開文檔時要調用的方法。


下面我們就來自己寫一個處理器來解析上面的XML文檔。首先我們需要將每個節點封裝成一個實體對象:


  1. public class Student {
  2. private String name;

  3. private int age;

  4. private String sn;
  5. public String getName() {
  6. return name;
  7. }
  8. public void setName(String name) {
  9. this.name = name;
  10. }
  11. public int getAge() {
  12. return age;
  13. }
  14. public void setAge(int age) {
  15. this.age = age;
  16. }
  17. public String getSn() {
  18. return sn;
  19. }
  20. public void setSn(String sn) {
  21. this.sn = sn;
  22. }


  23. }


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


  1. public class MyHandler extends DefaultHandler {

  2. private List<Student> studentList;

  3. private boolean inStudent = false;

  4. private boolean studentName = false;

  5. private boolean studentAge = false;

  6. private boolean studentSN = false;

  7. private Student curStudent ;

  8. public MyHandler() {

  9. studentList = new ArrayList<Student>();
  10. }
  11. @Override
  12. public void startElement(String uri, String localName, String qName,
  13. Attributes attributes) throws SAXException {

  14. String tagName = localName.length() != 0 ? localName : qName;
  15. tagName = tagName.toLowerCase().trim();

  16. if(tagName.equals("student")) {
  17. inStudent = true;
  18. curStudent = new Student();
  19. }

  20. if(inStudent) {

  21. if(tagName.equals("name")) {
  22. studentName = true;
  23. }else if(tagName.equals("age")) {
  24. studentAge = true;
  25. }else if(tagName.equals("sn")) {
  26. studentSN = true;
  27. }
  28. }

  29. }

  30. @Override
  31. public void endElement(String uri, String localName, String qName)
  32. throws SAXException {

  33. String tagName = localName.length() != 0 ? localName : qName;
  34. tagName = tagName.toLowerCase().trim();

  35. if(tagName.equals("student")) {
  36. inStudent = true;
  37. studentList.add(curStudent);
  38. }

  39. if(inStudent) {

  40. if(tagName.equals("name")) {
  41. studentName = false;
  42. }else if(tagName.equals("age")) {
  43. studentAge = false;
  44. }else if(tagName.equals("sn")) {
  45. studentSN = false;
  46. }
  47. }
  48. }

  49. @Override
  50. public void characters(char[] ch, int start, int length)
  51. throws SAXException {

  52. if(studentName) {
  53. curStudent.setName(curStudent.getName() + new String(ch,start,length));
  54. }else if (studentAge) {
  55. curStudent.setAge(Integer.parseInt(new String(ch,start,length)));
  56. }else if(studentSN) {
  57. curStudent.setSn(curStudent.getSn() + new String(ch, start, length));
  58. }
  59. }
  60. }


如上面的代碼,我們使用了一系列的布爾標志變量來保存文檔的遍歷狀態,先從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>張&nbsp;三</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. List<Student> list;
  5. reader.setContentHandler(myHandler);
  6. reader.parse(new InputSource(new URL(url).openStream()));

  7. list = myHandler.getStudentList();


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

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

另外下面是SAX的一個官方網站,裡面有一些介紹和代碼示例,英文不錯的童鞋可以來這裡參考一下:loveliness:
http://www.saxproject.org/
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved