Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發實例 >> Android應用開發入門(十二)使用SAX解析XML

Android應用開發入門(十二)使用SAX解析XML

編輯:Android開發實例

前言

  既然要說XML解析,那麼先來聊聊什麼是XML。XML,可擴展標記語言 (Extensible Markup Language) ,用於標記電子文件使其具有結構性的標記語言,可以用來標記數據、定義數據類型,是一種允許用戶對自己的標記語言進行定義的源語言,這是百度百科的解釋。而XML是一種在Internet中傳輸數據的常見格式,它與HTML一樣,都是SGML(標准通用標記語言),無論你是需要通過Internet訪問數據,或者發送數據給Web服務,都可能需要用到XML的知識。恰恰Android應用程序需要和網絡交互,否則只是一款單機的無互動的應用程序,所以很可能在Android應用程序開發的過程中使用到XML。

  由於XML的擴展性強,致使它需要有穩定的基礎規則來支持擴展,該語法規則需要注意的是:

  1. 開始和結束標簽匹配。
  2. 嵌套標簽不能相互嵌套。
  3. 區分大小寫。

Android中的XML

  Android平台最大的優勢在於,上層應用基本可以利用Java編程語言開發,Java平台支持通過許多不同的方式來使用XML,並且大多數與XML相關的API已經在Android系統上得到了完全的支持。但是因為Android這個移動設備的局限性,一般僅考慮使用三種方式解析XML:

  1. DOM,Document Object Model,文檔對象模型方式,解析完的XML將生成一個樹狀結構的對象。
  2. SAX,simple API for  Xml,以事件的形式通知程序,對XML進行解析。
  3. XML PULL,類似於SAX方式,程序以拉取的方式對XML進行解析。

SAX

  SAX是一種以事件驅動的XML API,由它定義的事件流可以指定從解析器傳到專門的處理程序的代碼的XML結構,簡單來講,它是解析速度快,占用內存少的接解析器,這種解析器比較適合Android等移動設備。

  使用SAX的優點:

  因為SAX的優勢是流的方式處理,當遇到一個標簽的時候,並不會記錄下之前所碰到的標簽。也就是說,在每個節點讀取會觸發的startElement()方法中,所能知道的信息,僅僅是當前的簽名的名字和屬性,至於標簽嵌套的結構,上層標簽的名字,是否有子元素與其他結構相關的信息,都是不知道的。      使用SAX解析XML的簡單步驟:
  1. 新建一個類MyHandler,繼承自DefaultHandler,並重寫DefaultHandler中的特有方法,解析XML的工作在此類中完成。
  2. 實例化一個SAX解析器的工廠對象,SAXParserFactory對象,使用SAXParserFactory.newInstance()方法獲取。
  3. 利用SAXParserFactory.newSAXParser()獲得SAX解析器對象SAXParser。
  4. 實例化MyHandler類,傳入需要解析的節點名稱。
  5. 使用SAXParser.parse()方法設置待解析的XML流和XML解析對象。
  6. 最後從MyHandler對象中獲得解析結果。
  現在詳細講解一下上面提到的類的作用。   DefaultHandler類是SAX2事件處理程序的默認基類。它繼承了EntityResolver、DTDHandler、ContentHandler和ErrorHandler這四個接口。包含這四個接口的所有方法,所以我們在編寫事件處理程序時,可以不用直接實現這四個接口,而繼承該類,然後重寫我們需要的方法。   而在DefaultHandler中的繼承類中,具體需要重寫的方法有以下幾個:
  • public void startDocument():接受到一個XML文檔時候的通知。
  • public void startElement(String uri, String localName, String qName,Attributes attributes):接受到一個開始元素的通知,並且可以在此獲得元素的屬性。
  • public void characters(char[] ch, int start, int length):接收元素中字符數據的通知。
  • public void endElement(String uri, String localName, String qName):接收結束元素的通知。
  • public void endDocument():接受一個文檔的結束通知。

  上面一些重寫的方法通過一個XML文件來講解一下什麼時候被執行。

<?xml version="1.0" encoding="utf-8"?>               startDocument
<persons>                                                          startElement
 <person id="23">                                               startElement
  <name nameid="1">                                          startElement
   Jack                                                                 characters
  </name>                                                           endElement
  <age>                                                               startElement
   21                                                                   characters
  </age>                                                             endElement
 </person>                     endElement       
</persons>                     endElement

  SAXParserFactory類,定義了一個工廠API,使應用程序能夠配置和獲得基於SAX的解析器以解析XML文檔。它只有一個prctected的構造方法(單例模式),所以需要使用靜態的newInstance()方法來回的SAXParserFactory()對象。使用SAXParserFactory可以通過調用.newSAXParser()方法獲得一個SAXParser,通過SAXParser對象可以執行parser()方法,通過傳遞的參數設定XML流和解析器類。

示例程序

  現在通過一個示例程序來講解一下SAX是怎麼解析XML文件的,這個示例程序是運行在Android平台上的,為了模擬真實情況,在IIS服務器上放置了一個靜態的XML文件,通過Android程序去讀取XML文件中的內容,在這個示例程序中,讀取person節點的值。因為是Android程序,所以別忘了賦予其訪問網絡的權限。

  XML文件內容:

  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <persons> 
  3. <person id="23"> 
  4. <name nameid="1">Jack</name> 
  5. <age>21</age> 
  6. </person> 
  7. <person id="20"> 
  8. <name nameid="2">Dick</name> 
  9. <age>23</age> 
  10. </person> 
  11. </persons> 

  步驟一,DefaultHandler類的繼承子類MyHandler:

  1. package cn.bgxt.handler;  
  2.  
  3. import java.util.ArrayList;  
  4. import java.util.HashMap;  
  5. import java.util.List;  
  6.  
  7. import org.xml.sax.Attributes;  
  8. import org.xml.sax.SAXException;  
  9. import org.xml.sax.helpers.DefaultHandler;  
  10.  
  11. public class MyHandler extends DefaultHandler {  
  12.  
  13.     private List<HashMap<String, String>> list = null; //解析後的XML內容  
  14.     private HashMap<String, String> map = null;  //存放當前需要記錄的節點的XML內容  
  15.     private String currentTag = null;//當前讀取的XML節點  
  16.     private String currentValue = null;//當前節點的XML文本值  
  17.     private String nodeName = null;//需要解析的節點名稱  
  18.  
  19.     public MyHandler(String nodeName) {  
  20.         // 設置需要解析的節點名稱  
  21.         this.nodeName = nodeName;  
  22.     }  
  23.  
  24.     @Override 
  25.     public void startDocument() throws SAXException {  
  26.         // 接收文檔開始的通知。  
  27.         // 實例化ArrayList用於存放解析XML後的數據  
  28.         list = new ArrayList<HashMap<String, String>>();  
  29.     }  
  30.  
  31.     @Override 
  32.     public void startElement(String uri, String localName, String qName,  
  33.             Attributes attributes) throws SAXException {  
  34.         // 接收元素開始的通知。          
  35.         if (qName.equals(nodeName)) {  
  36.             //如果當前運行的節點名稱與設定需要讀取的節點名稱相同,則實例化HashMap  
  37.             map = new HashMap<String, String>();  
  38.         }  
  39.         //Attributes為當前節點的屬性值,如果存在屬性值,則屬性值也讀取。  
  40.         if (attributes != null && map != null) {  
  41.             for (int i = 0; i < attributes.getLength(); i++) {  
  42.                 //讀取到的屬性值,插入到Map中。  
  43.                 map.put(attributes.getQName(i), attributes.getValue(i));  
  44.             }  
  45.         }  
  46.         //記錄當前節點的名稱。  
  47.         currentTag = qName;  
  48.     }  
  49.  
  50.     @Override 
  51.     public void characters(char[] ch, int start, int length)  
  52.             throws SAXException {  
  53.         // 接收元素中字符數據的通知。  
  54.         //當前節點有值的情況下才繼續執行  
  55.         if (currentTag != null && map != null) {  
  56.             //獲取當前節點的文本值,ch這個直接數組就是存放的文本值。  
  57.             currentValue = new String(ch, start, length);  
  58.             if (currentValue != null && !currentValue.equals("")  
  59.                     && !currentValue.equals("\n")) {  
  60.                 //讀取的文本需要判斷不能為null、不能等於”“、不能等於”\n“  
  61.                 map.put(currentTag, currentValue);  
  62.             }  
  63.         }  
  64.         //讀取完成後,需要清空當前節點的標簽值和所包含的文本值。  
  65.         currentTag = null;  
  66.         currentValue = null;  
  67.     }  
  68.  
  69.     @Override 
  70.     public void endElement(String uri, String localName, String qName)  
  71.             throws SAXException {  
  72.         // 接收元素結束的通知。  
  73.         if (qName.equals(nodeName)) {  
  74.             //如果讀取的結合節點是我們需要關注的節點,則把map加入到list中保存  
  75.             list.add(map);  
  76.             //使用之後清空map,開始新一輪的讀取person。  
  77.             map = null;  
  78.         }  
  79.     }  
  80.  
  81.     public List<HashMap<String, String>> getList() {  
  82.         return list;  
  83.     }  
  84.  

  因為XML文件是放在服務器上的,需要寫一個HttpUitils類讀取服務器上XML文件,使用的是URLHttpConnection的方式讀取,如果不了解URLHttpConnection的朋友,可以看之前的文章:http://www.fengfly.com/plus/view-213371-1.html。下面直接附上代碼:

  1. package cn.bgxt.http;  
  2.  
  3. import java.io.InputStream;  
  4. import java.net.HttpURLConnection;  
  5. import java.net.URL;  
  6.  
  7. public class HttpUtils {  
  8.  
  9.     public HttpUtils() {  
  10.     }  
  11.     public static InputStream getXML(String path) {  
  12.         try {  
  13.             URL url=new URL(path);  
  14.             if(url!=null)  
  15.             {  
  16.                 HttpURLConnection connection=(HttpURLConnection)url.openConnection();  
  17.                 connection.setDoInput(true);  
  18.                 connection.setConnectTimeout(3000);  
  19.                 connection.setRequestMethod("GET");  
  20.                 int requesetCode=connection.getResponseCode();  
  21.                 if(requesetCode==200)  
  22.                 {  
  23.                     //如果執行成功,返回HTTP響應流  
  24.                     return connection.getInputStream();  
  25.                 }  
  26.             }  
  27.         } catch (Exception e) {  
  28.             // TODO: handle exception  
  29.         }          
  30.         return null;  
  31.     }  

  還需要一個調用SAXParser對象的類,這裡新建一個SaxService類,實例化SAXParserFactory用於設定XML流和解析器。代碼如下:

  1. package cn.bgxt.service;  
  2.  
  3. import java.io.InputStream;  
  4. import java.util.HashMap;  
  5. import java.util.List;  
  6.  
  7. import javax.xml.parsers.SAXParser;  
  8. import javax.xml.parsers.SAXParserFactory;  
  9.  
  10. import cn.bgxt.handler.MyHandler;  
  11.  
  12. public class SaxService {  
  13.  
  14.     public SaxService() {  
  15.         // TODO Auto-generated constructor stub  
  16.     }  
  17.       
  18.     public static List<HashMap<String, String>> readXML(InputStream inputStream,String nodeName)  
  19.     {  
  20.         try {  
  21.             //實例化SAX工廠類  
  22.             SAXParserFactory factory=SAXParserFactory.newInstance();  
  23.             //實例化SAX解析器。  
  24.             SAXParser sParser=factory.newSAXParser();  
  25.             //實例化DefaultHandler,設置需要解析的節點  
  26.             MyHandler myHandler=new MyHandler(nodeName);  
  27.             // 開始解析  
  28.             sParser.parse(inputStream, myHandler);  
  29.             // 解析完成之後,關閉流  
  30.             inputStream.close();  
  31.             //返回解析結果。  
  32.             return myHandler.getList();  
  33.         } catch (Exception e) {  
  34.             // TODO: handle exception  
  35.         }          
  36.         return null;  
  37.     }  
  38.       

 最後就是Android的一個Activity類了,布局界面很簡單,只有一個按鈕控件,這裡不展示布局代碼了。點擊按鈕後,觸發點擊事件,因為是Android4.0+,所以不能在主線程中訪問網絡,需要另起一個線程,這裡使用Thread類。代碼如下: 

  1. package cn.bgxt.androidxmlforsax;  
  2.  
  3. import java.io.InputStream;  
  4. import java.util.HashMap;  
  5. import java.util.List;  
  6. import cn.bgxt.http.HttpUtils;  
  7. import cn.bgxt.service.SaxService;  
  8. import android.os.Bundle;  
  9. import android.app.Activity;  
  10. import android.view.Menu;  
  11. import android.view.View;  
  12. import android.widget.Button;  
  13.  
  14. public class MainActivity extends Activity {  
  15.     private Button btn;  
  16.     @Override 
  17.     protected void onCreate(Bundle savedInstanceState) {  
  18.         super.onCreate(savedInstanceState);  
  19.         setContentView(R.layout.activity_main);  
  20.           
  21.         btn=(Button)findViewById(R.id.btn);  
  22.         btn.setOnClickListener(new View.OnClickListener() {  
  23.               
  24.             @Override 
  25.             public void onClick(View v) {  
  26.                 //Android4.0+需要另起線程訪問網絡  
  27.                 Thread thread=new Thread(new Runnable() {  
  28.                       
  29.                     @Override 
  30.                     public void run() {  
  31.                         // 設置XML文檔的位置  
  32.                         String path="http://192.168.1.107:1231/persons.xml";  
  33.                         //讀取服務器上的XML,獲取XML流  
  34.                         InputStream inputStream=HttpUtils.getXML(path);  
  35.                         try {  
  36.                             //解析流,設定需要解析的節點  
  37.                             List<HashMap<String, String>> list=SaxService.readXML(inputStream, "person");  
  38.                             for(HashMap<String,String> map:list)  
  39.                             {  
  40.                                 //打印到LogCat中  
  41.                                 System.out.println(map.toString());  
  42.                             }  
  43.                         } catch (Exception e) {  
  44.                             // TODO: handle exception  
  45.                         }  
  46.                     }  
  47.                 });  
  48.                 thread.start();                  
  49.             }  
  50.         });          
  51.     }  
  52.  
  53.     @Override 
  54.     public boolean onCreateOptionsMenu(Menu menu) {  
  55.         // Inflate the menu; this adds items to the action bar if it is present.  
  56.         getMenuInflater().inflate(R.menu.main, menu);  
  57.         return true;  
  58.     }  
  59.  

 當點擊後,XML解析後的內容會把打印到日志中,可以使用LogCat查看。

  示例程序的下載

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved