Android XML文檔解析(一)——SAX解析

 ------------------------------------------------------------------------------------------------------

       此文章僅作爲學習交流所用

       轉載或引用請務必註明原文地址:

       http://blog.csdn.net/luzhenrong45/article/details/11851607      

       或聯繫作者:[email protected] 

       謝謝!                       

     ------------------------------------------------------------------------------------------------------

  

 一. XML介紹

      XML:extensible markup language,可擴展標記語言. 與HTML(超文本標記語言,即Hypertext Markup Language)一樣,XML也是標準通用標記語言 (SGML) 的子集,非常適合 Web 傳輸。XML與HTML的設計區別是:XML 被設計爲傳輸和存儲數據,其焦點是數據的內容。而HTML 被設計用來顯示數據,其焦點是數據的外觀。HTML 旨在顯示信息,而 XML 旨在傳輸信息。XML 提供統一的方法來描述和交換獨立於應用程序或供應商的結構化數據。其目的是爲了促進Internet上結構化文檔的交換。簡單的說,XML是一組規則和準則的集合,用於以無格式文本來描述結構化數據.

      XML是純數據描述,與編程語言、操作系統或傳輸協議無關,從而將數據從以代碼爲中心的基礎結構所產生的約束中解放出來,讓數據能夠在Web上更自由的流通。然而XML本身只是以純文本對數據進行編碼的一種格式,要想利用XML,或者說利用XML文件中所編碼的數據,必須先將數據從純文本中解析出來,因此,必須有一個能夠識別XML文檔中信息的解析器,用來解釋XML文檔並提取其中的數據。根據數據提取的不同需求,又存在着多種解析方式,不同的解析方式有着各自的優缺點和適用環境。選擇合適的XML解析技術能夠有效提升應用系統的整體性能.在Android中,常見的XML解析器分別爲SAX解析器、DOM解析器和PULL解析器.

    下面,介紹SAX解析方式.

二.  SAX解析

      SAX,全稱Simple API for XML,既是指一種接口,也是指一個軟件包。 這種方式解析是一種基於事件驅動的api,有兩個部分,解析器和事件處理器,解析器就是XMLReader接口,負責讀取XML文檔,和向事件處理器發送事件(也是事件源),事件處理器ContentHandler接口,負責對發送的事件響應和進行XML文檔處理。SAX解析XML文件採用事件驅動的方式進行,也就是說,SAX是逐行掃描文件,當掃描到文檔(document)開始與結束、元素(element)開始與結束、文檔(document)結束等地方時回調你寫好的事件處理程序,然後繼續同樣的掃描,直至文檔結束。使用SAX的優勢在於其解析速度較快,佔用內存較少(相對於DOM而言)。而且SAX在解析文件的過程中得到自己需要的信息後可以隨時終止解析,並不一定要等文件全部解析完畢。凡事有利必有弊,其劣勢在於SAX採用的是流式處理方式,當遇到某個標籤的時候,它並不會記錄下以前所遇到的標籤,也就是說,在處理某個標籤的時候,比如在 startElement方法中,所能夠得到的信息就是標籤的名字和屬性,至於標籤內部的嵌套結構,上層標籤、下層標籤以及其兄弟節點的名稱等等與其結構相關的信息都是不得而知的。實際上就是把XML文件的結構信息丟掉了,如果需要得到這些信息的話,只能你自己在程序裏進行處理了。所以相對DOM而言,SAX處理XML文檔沒有DOM方便,SAX處理的過程相對DOM而言也比較複雜。

 


 

//用於處理文檔解析開始事件

public void startDocument()throws SAXException

//處理元素開始事件,從參數中可以獲得元素所在名稱空間的uri,元素名稱,屬性類表等信息

public void startElement(String namespacesURI , String localName , String qName , Attributes atts) throws SAXException

//處理元素結束事件,從參數中可以獲得元素所在名稱空間的uri,元素名稱等信息

public void endElement(String namespacesURI , String localName , String qName) throws SAXException
//處理元素的字符內容,從參數中可以獲得內容

public void characters(char[] ch , int start , int length)  throws SAXException

//當文檔結束的時候,調用這個方法,可以在其中做一些善後的工作
public void endDocument() throws SAXException 

 

                                  

 

 

三. SAX解析XML步驟

    Android 使用SAX解析XML文件有兩種方式,第一是直接使用SAXParser,或者創建一個XMLReader.不管採用哪種方式,前面三個步驟是一樣的.

(一)第一步:加載需要解析的文件,將一個xml文檔或者資源變成一個java可以處理的InputStream流.比如我的xml文件名是laolu_xml.xml,放在src目錄下,可通過類裝載器的方式獲得文件路徑,再獲得文件的輸入流

InputStream is= this.getClass().getClassLoader().getResourceAsStream("laolu_xml.xml");

(二)第二步:新建一個工廠類SAXParserFactory

SAXParserFactory factory = SAXParserFactory.newInstance();

(三)第三步:讓工廠類產生一個SAX的解析類SAXParser

SAXParser saxParser = factory.newSAXParser();

(四)第四步:可以採用XMLReader解析或直接使用SAXParser解析.

 

 (1)採用XMLReader

1) 從SAXPsrser中得到一個XMLReader實例

XMLReader xmlReader = saxParser.getXMLReader();

2) 把自己寫的handler註冊到XMLReader中,一般最重要的就是ContentHandler:

SAXForHandler handler = new SAXForHandler ();  //SAXForHandler爲自己寫的SAX解析類
xmlReader.setContentHandler(handler);
3) 開始解析XML
xmlReader.parse(new InputSource(is));

 

(2)直接使用SAXParser解析

SAXForHandler handler = new SAXForHandler ();
saxParser.parse(is,handler);
 

兩種方式都可以對XML文件進行解析,使用的效果是完全一樣的.其實SAXParser是JAXP(JAVA API for XML Processing) 對XMLReader的一個封裝,只不過,SAXParser能接受更多類型的參數,能方便對不同數據源的XML文檔進行解析,使用XMLReader要稍微煩瑣一些.

 

四.SAX解析實例.

(一)下面以一個工程實例來實現SAX對XML文件的解析.新建一個xml文件: laolu_xml.xml,該文件放在工程根目錄下面.內容如下:

<?xml version="1.0"  encoding="UTF-8"?>
<persons>
    <person id="0">
        <name>劉德華</name>
        <sex>男</sex>
        <age>21</age>
    </person>
    <person id="1">
        <name>張漫玉</name>
        <sex>女</sex>
        <age>22</age>
    </person>
    <person id="2">
        <name>張易謀</name>
        <sex>男</sex>
        <age>23</age>
    </person>
    <person id="3">
        <name>周新馳</name>
        <sex>未知</sex>
        <age>24</age>
    </person>
    <person id="4">
        <name>納蘭容若</name>
        <sex>男</sex>
        <age>25</age>
    </person>
</persons>


(二)先看一下實際效果圖,Android對於XML解析,主要有sax,dom,pull三種方式,這裏只介紹sax方式.其他兩種以後再介紹.

 

(三)工程源碼框架

(1)佈局文件:

 main_xml.xml  

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
     android:orientation="vertical"
    tools:context=".XML_ParseActivity" >
    
     <TextView
	     android:layout_width="wrap_content"
	     android:layout_height="wrap_content"
	     android:text="@string/hello_world" />
     <Button
	     android:id="@+id/sax_btn" 
	     android:layout_width="match_parent"
	     android:layout_height="wrap_content"
	     android:text="@string/sax_parse"/>
     <Button
         android:id="@+id/dom_btn"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:text="@string/dom_parse"
        />
      <Button   
         android:id="@+id/pull_btn"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:text="@string/pull_parse"
        />  
      <ListView  
         android:id="@+id/listview"  
         android:layout_width="fill_parent"  
         android:layout_height="wrap_content" >  
      </ListView>  
            
    </LinearLayout>
    


listview_xml.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:layout_width="fill_parent"  
    android:layout_height="fill_parent"  
    android:orientation="horizontal" >  
  
    <View  
        android:layout_width="0.5px"  
        android:layout_height="fill_parent"  
        android:background="#B8B8B8"  
        android:visibility="visible" />  
        
     <TextView
         android:id="@+id/id"
         android:layout_width="60dip"
         android:layout_height="40dip"
         />
     <View  
        android:layout_width="0.5px"  
        android:layout_height="fill_parent"  
        android:background="#B8B8B8"  
        android:visibility="visible" />  
        
     <TextView
         android:id="@+id/name"
         android:layout_width="120dip"
         android:layout_height="40dip"
         />
     
     <View  
        android:layout_width="0.5px"  
        android:layout_height="fill_parent"  
        android:background="#B8B8B8"  
        android:visibility="visible" />  
        
     <TextView
         android:id="@+id/sex"
         android:layout_width="60dip"
         android:layout_height="40dip"
         />
     
     <View  
        android:layout_width="0.5px"  
        android:layout_height="fill_parent"  
        android:background="#B8B8B8"  
        android:visibility="visible" />  
        
     <TextView
         android:id="@+id/age"
         android:layout_width="120dip" 
         android:layout_height="40dip"
         />
   
        
</LinearLayout>


(2)這裏重寫了SimpleAdapter適配器,使用ListView的效果更好看一點.當然,這一點跟今天的主題沒關.

MySimpleAdapter.java

package com.laolu.adapter;

import java.util.List;
import java.util.Map;

import android.content.Context;
import android.graphics.Color;
import android.view.View;
import android.view.ViewGroup;
import android.widget.SimpleAdapter;


public class MySimpleAdapter extends SimpleAdapter
{

	public MySimpleAdapter(Context context,
			List<? extends Map<String, ?>> data, int resource, String[] from,
			int[] to) 
	{
		super(context, data, resource, from, to);
	} 

	@Override
	public View getView(int position, View convertView, ViewGroup parent) 
	{
		View view=null;
		if(convertView!=null)
		{
			view=convertView;
		}else
		{
			view=super.getView(position,convertView,parent);
			
		}
		int colors[]={Color.GRAY,Color.WHITE}; 
		view.setBackgroundColor(colors[position%2]);  // 每個item之間顏色不同  
		
		return super.getView(position, view, parent);//返回自己的view
		
	}
	
}


(3)自己實現的SAX解析類SAXForHandler,繼承DefaultHandler,而DefaultHandler是實現了ContenHandler的接口的.ContentHandler提供了之前所說的相應的事件方法,所以這個類是最重要的.因爲這些回調函數都是自己寫代碼實現的.

SAXForHandler.java

package com.laolu.parser;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import android.util.Log;

public class SAXForHandler extends DefaultHandler
{
	private static final String TAG="SAXForHandler";
	private List<Map<String,Object>> persons;
	private Map<String,Object> person;
	
	private String nowWitch;
	public List<Map<String,Object>> getPersons()
	{
		return persons;
	}
	
	@Override
	public void startDocument() throws SAXException {
		persons=new ArrayList<Map<String,Object>>();
		Log.i(TAG,"***startDocument()***");
	}
	@Override
	public void startElement(String uri, String localName, String qName,
			Attributes attributes) throws SAXException 
	{
		if("person".equals(localName))
		{
			for(int i=0;i<attributes.getLength();i++)
			{
				Log.i(TAG,"arrtributes: "+attributes.getLocalName(i)+"_attributes_Value"
			        +attributes.getValue(i));
				person=new HashMap<String,Object>();
				person.put("id", attributes.getValue(i));
				
			}
		}
		nowWitch=localName;
		Log.i(TAG, qName+"***startElement()***");

	}
	@Override
	public void characters(char[] ch, int start, int length) 
			throws SAXException {
		String data=new String(ch,start,length).trim();
		if(!"".equals(data.trim()))
		{
			Log.i(TAG, "content: "+data.trim());
		}
		if("name".equals(nowWitch))
		{
			person.put("name", data.trim());
		}else if("age".equals(nowWitch))
		{
			person.put("age", data.trim());
		}else if("sex".equals(nowWitch))
		{
			person.put("sex", data.trim());
		}

	}
	
	@Override
	public void endElement(String uri, String localName, String qName)
			throws SAXException {
		Log.i(TAG,qName+"***endElement()***");
		if("person".equals(localName))
		{
			persons.add(person);
			person=null;
		}
		nowWitch=null;
	}
	@Override
	public void endDocument() throws SAXException {
		Log.i(TAG, "***endDocument()***");
	}
	  
}


(4)主Activity,按下按鍵,ListView顯示解析結果.

package com.laolu.main;

import java.io.InputStream;
import java.util.List;
import java.util.Map;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import com.example.xml.R;
import com.laolu.adapter.MySimpleAdapter;
import com.laolu.parser.SAXForHandler;

import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView;

public class XML_ParseActivity extends Activity
{
	private static final String SAX="SAX_Parse";
	private static final String DOM="DOM_Parse";
	private static final String PULL="Pull_Parse";
	ListView listView;

	@Override
	protected void onCreate(Bundle savedInstanceState) 
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main_xml);
		listView=(ListView) findViewById(R.id.listview);
		
		Button saxButton=(Button) findViewById(R.id.sax_btn);
		Button domButton=(Button) findViewById(R.id.dom_btn);
		Button pullButton=(Button) findViewById(R.id.pull_btn);
		saxButton.setOnClickListener(new MyListener());
		domButton.setOnClickListener(new MyListener());
		pullButton.setOnClickListener(new MyListener());
	}
	
	public class MyListener implements OnClickListener
	{

		@Override
		public void onClick(View v)
		{
			switch (v.getId())
			{
			case R.id.sax_btn:
				try{
					updateListViewBySAX();
				}catch(Exception e)
				{
					Log.i(SAX,"SAX Exception!!!");
				}
				break;
			case R.id.dom_btn:
				break;
			case R.id.pull_btn:
				break;
			
			}
				
		}
		
	}
	public void updateListViewBySAX() throws Exception
	{
		InputStream inputStream = this.getClass().getClassLoader().
		getResourceAsStream("laolu_xml.xml");
		SAXForHandler saxForHandler = new SAXForHandler();
		SAXParserFactory spf = SAXParserFactory.newInstance();
		SAXParser saxParser = spf.newSAXParser();
		saxParser.parse(inputStream, saxForHandler);//採用
		
		
		List<Map<String,Object>> persons = saxForHandler.getPersons();
		SimpleAdapter simpleAdapter=new MySimpleAdapter(this, persons, R.layout.listview_xml, 
	     new String[]{"id","name","sex","age"}, new int[]{R.id.id,R.id.name,R.id.sex,R.id.age});
		listView.setAdapter(simpleAdapter);
		inputStream.close();

	}
	
}


 

 

 

 

 

 

 

 

 

         

發佈了60 篇原創文章 · 獲贊 173 · 訪問量 30萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章