国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

詳解android使用SAX解析XML文件

2019-12-12 04:43:58
字體:
來源:轉載
供稿:網友

解析XML的方式有很多種,大家比較熟悉的可能就是DOM解析。

DOM(文件對象模型)解析:解析器讀入整個文檔,然后構建一個駐留內存的樹結構,然后代碼就可以根據DOM接口來操作這個樹結構了。

優點:整個文檔讀入內存,方便操作:支持修改、刪除和重現排列等多種功能。

缺點:將整個文檔讀入內存中,保留了過多的不需要的節點,浪費內存和空間。

使用場合:一旦讀入文檔,還需要多次對文檔進行操作,并且在硬件資源充足的情況下(內存,CPU)。

為了解決DOM解析存在的問題,就出現了SAX解析。其特點為:

優點:不用實現調入整個文檔,占用資源少。尤其在嵌入式環境中,如android,極力推薦使用SAX解析。

缺點:不像DOM解析一樣將文檔長期駐留在內存中,數據不是持久的。如果事件過后沒有保存數據,數據就會丟失。

使用場合:機器有性能限制。

SAX解析XML文檔采用事件驅動模式。什么是事件驅動模式?它將XML文檔轉換成一系列的事件,由單獨的事件處理器來決定如何處理。

基于事件驅動的處理模式主要是基于事件源和事件處理器(或者叫監聽器)來工作的。一個可以產生事件的對象叫做事件源,而一個可以針對事件做出響應的對象就被叫做事件處理器。

在SAX接口中,事件源是org.xml.sax包中的XMLReader,他通過parse()方法開始解析XML文檔,并根據文檔內容產生事件。而事件處理器則是org.xml.sax包中的ContentHandler、DTDHandler、ErrorHandler,以及EntityResolver這四個接口。他們分別處理事件源在解析過程中產生不同類的事件(其中DTDHandler為解析文檔DTD時所用)。詳細介紹如下表:

在上述四個接口中,最重要的就是ContentHandler這個接口,下面是對這個接口方法的說明:

//設置一個可以定位文檔內容事件發生位置的定位器對象public void setDocumentLocator(Locator locator)//用于處理文檔解析開始事件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

這里再介紹下XMLReader中的方法。

//注冊處理XML文檔解析事件ContentHandlerpublic void setContentHandler(ContentHandler handler)//開始解析一個XML文檔public void parse(InputSorce input) throws SAXException

SAX實現實體解析的步驟:

在android中使用SAX是有跡可循的,完全可以按照下面的方法就可以輕松找到xml里的tag,然后得到想要的內容。具體實現步驟如下:

(一)第一步:新建一個工廠類SAXParserFactory,代碼如下:

SAXParserFactory factory = SAXParserFactory.newInstance();

(二)第二步:讓工廠類產生一個SAX的解析類SAXParser,代碼如下:

SAXParser parser = factory.newSAXParser();

(三)第三步:從SAXPsrser中得到一個XMLReader實例,代碼如下:

XMLReader reader = parser.getXMLReader();

(四)第四步:把自己寫的handler注冊到XMLReader中,一般最重要的就是ContentHandler,代碼如下:

RSSHandler handler = new RSSHandler();reader.setContentHandler(handler);

(五)第五步:將一個xml文檔或者資源變成一個java可以處理的InputStream流后,解析正式開始,代碼如下:

parser.parse(is);

上面幾個步驟中,最重要、最關鍵的就是第四步,handler的實現。

下面通過一個RSS解析的例子說明handler的實現:

我們先是自己見一個rss的xml文檔,實現本地解析,新建的rss文檔如下:

<?xml version="1.0" encoding="UTF-8"?>  <channel>    <title>RSS 解析練習</title>    <description>hehehaha</description>    <link>http://www.cnblogs.com/felix-hua/</link>    <language>zh-cn</language>    <item>      <title><![CDATA[頭條]]></title>      <link>http://mc.cz001.com.cn/images/menu/23_active.png</link>      <category>0</category>      <description>描述詳細信息的</description>      <pubDate>2012-01-09</pubDate>    </item>        <item>      <title><![CDATA[新聞]]></title>      <link>http://mc.cz001.com.cn/images/menu/23_active.png</link>      <category>0</category>      <description>描述詳細信息的</description>      <pubDate>2012-01-09</pubDate>    </item>        <item>      <title><![CDATA[首頁]]></title>      <link>http://mc.cz001.com.cn/images/menu/23_active.png</link>      <category>0</category>      <description>描述詳細信息的</description>      <pubDate>2012-01-09</pubDate>    </item>        <item>      <title><![CDATA[財經]]></title>      <link>http://mc.cz001.com.cn/images/menu/23_active.png</link>      <category>0</category>      <description>描述詳細信息的</description>      <pubDate>2012-01-09</pubDate>    </item>

建好后,我們命名為rssxml.xml,然后放到項目的根目錄下:

然后我們可以建立兩個實體類:

1、RSSFeed,與完整的xml文檔相對應;

2、RSSItem,與item標簽內的信息相對應。

這樣在解析xml時,我們就可以把解析出來的信息放到實體類里,然后直接操作實體類就可以了。下面給出代碼:

RSSFeed.java

package com.sax.org.entity;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.Vector;public class RSSFeed {  private String title;  private int itemcount;  private List<RSSItem> itemlist;    public RSSFeed(){    itemlist = new Vector<RSSItem>(0);  }    /**   * 負責將一個RSSItem加入到RSSFeed類中   * @param item   * @return   */  public int addItem(RSSItem item){    itemlist.add(item);    itemcount++;    return itemcount;  }    public RSSItem getItem(int location){    return itemlist.get(location);  }    public List<RSSItem> getAllItems(){    return itemlist;  }    /**   * 負責從RSSFeed類中生成列表所需要的數據   * @return   */  public List getAllItemForListView(){    List<Map<String, Object>> data = new ArrayList<Map<String,Object>>();    int size = itemlist.size();    for(int i=0 ; i<size ; i++){      HashMap<String , Object> item = new HashMap<String, Object>();      item.put(RSSItem.TITLE, itemlist.get(i).getTitle());      item.put(RSSItem.PUBDATE, itemlist.get(i).getPubdate());      data.add(item);    }    return data;  }  public String getTitle() {    return title;  }  public void setTitle(String title) {    this.title = title;  }  public int getItemcount() {    return itemcount;  }  public void setItemcount(int itemcount) {    this.itemcount = itemcount;  }  public List<RSSItem> getItemlist() {    return itemlist;  }  public void setItemlist(List<RSSItem> itemlist) {    this.itemlist = itemlist;  }  }

RSSItem.java

package com.sax.org.entity;public class RSSItem {  public static String TITLE = "title";  public static String PUBDATE = "pubdate";  public String title;  public String description;  public String link;  public String category;  public String pubdate;  public RSSItem() {  }  public String getTitle() {    return title;  }  public void setTitle(String title) {    this.title = title;  }  public String getDescription() {    return description;  }  public void setDescription(String description) {    this.description = description;  }  public String getLink() {    return link;  }  public void setLink(String link) {    this.link = link;  }  public String getCategory() {    return category;  }  public void setCategory(String category) {    this.category = category;  }  public String getPubdate() {    return pubdate;  }  public void setPubdate(String pubdate) {    this.pubdate = pubdate;  }    }

下面就是最最重要的地方了,建立自己的ContentHandler.看下面的代碼:

RSSHandler.java

package com.sax.org.handler;import org.xml.sax.Attributes;import org.xml.sax.SAXException;import org.xml.sax.helpers.DefaultHandler;import com.sax.org.entity.RSSFeed;import com.sax.org.entity.RSSItem;public class RSSHandler extends DefaultHandler{  RSSFeed RssFeed;  RSSItem RssItem;  final int RSS_TITLE = 1;  final int RSS_LINK = 2;  final int RSS_DESCRIPTION = 3;  final int RSS_CATEGORY = 4;  final int RSS_PUBDATE = 5;  int currentstate = 0;    public RSSHandler(){}    public RSSFeed getFeed(){    return RssFeed;  }    @Override  public void startDocument() throws SAXException {    // TODO Auto-generated method stub    RssFeed = new RSSFeed();    RssItem = new RSSItem();  }    @Override  public void endDocument() throws SAXException {    // TODO Auto-generated method stub      }    @Override  public void startElement(String uri, String localName, String qName,      Attributes attributes) throws SAXException {    // TODO Auto-generated method stub    if(localName.equals("channel")){      currentstate = 0;      return;    }    if(localName.equals("item")){      RssItem = new RSSItem();      return;    }    if(localName.equals("title")){      currentstate = RSS_TITLE;      return;    }    if(localName.equals("description")){      currentstate = RSS_DESCRIPTION;      return;    }    if(localName.equals("link")){      currentstate = RSS_LINK;      return;    }    if(localName.equals("category")){      currentstate = RSS_CATEGORY;      return;    }    if(localName.equals("pubDate")){      currentstate = RSS_PUBDATE;      return;    }    currentstate = 0;  }    @Override  public void endElement(String uri, String localName, String qName)      throws SAXException {    // TODO Auto-generated method stub    if(localName.equals("item")){      RssFeed.addItem(RssItem);      return;    }  }    @Override  public void characters(char[] ch, int start, int length)      throws SAXException {    // TODO Auto-generated method stub    String theString = new String(ch, start, length);    switch(currentstate){    case RSS_TITLE:      RssItem.setTitle(theString);      currentstate = 0;      break;    case RSS_DESCRIPTION:      RssItem.setDescription(theString);      currentstate = 0;      break;    case RSS_LINK:      RssItem.setLink(theString);      currentstate = 0;      break;    case RSS_PUBDATE:      RssItem.setPubdate(theString);      currentstate = 0;      break;    case RSS_CATEGORY:      RssItem.setCategory(theString);      currentstate = 0;      break;    default:      return;    }  }}

就上面的代碼分析,實現一個ContentHandler一般要一下幾個步驟:

1、聲明一個類,繼承DefaultHandler。DefaultHandler是一個基類,這個類里面簡單實現了一個ContentHandler。我們只需要重寫里面的方法即可。

2、重寫 startDocument() 和 endDocument(),一般解析將正式解析之前的一些初始化工資放到startDocument()里面,收尾的工作放到endDocument()里面。

3、重寫startElement(),XML解析器遇到XML里面的tag時就會調用這個函數。經常在這個函數內是通過localName倆進行判斷而操作一些數據。

4、重寫characters()方法,這是一個回調方法。解析器執行完startElement()后,解析完節點的內容后就會執行這個方法,并且參數ch[]就是節點的內容。這個例子里我們根據currentstate的不同,來判斷當前那個tag的內容,并放到合適的實體類中。

5、重寫endElement()方法,這個方法與startElement()相對應,解析完一個tag節點后,執行這個方法。再找個例子中,如果解析一個item結束,就將RSSIiem添加到RSSFeed中。

最后我們實現一個activity來展現解析的結果:

 package com.sax.org;import java.io.IOException;import java.net.URL;import javax.xml.parsers.ParserConfigurationException;import javax.xml.parsers.SAXParser;import javax.xml.parsers.SAXParserFactory;import org.xml.sax.InputSource;import org.xml.sax.SAXException;import org.xml.sax.XMLReader;import android.app.Activity;import android.os.Bundle;import android.widget.ListView;import android.widget.SimpleAdapter;import android.widget.TextView;import com.sax.org.entity.RSSFeed;import com.sax.org.entity.RSSItem;import com.sax.org.handler.RSSHandler;public class SAXReaderActivity extends Activity {  /** Called when the activity is first created. */  public String rssUrl = "http://mc.cz001.com.cn/a/indexconfig/index.rss";  public RSSFeed feed;  @Override  public void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.main);    feed = getFeed(rssUrl);    showList();  }  public RSSFeed getFeed(String rssUrl) {    try {// 這里我們實現了本地解析,所以注掉了這個取網絡數據的。//      URL url = new URL(rssUrl);      SAXParserFactory factory = SAXParserFactory.newInstance();      SAXParser parser = factory.newSAXParser();      XMLReader reader = parser.getXMLReader();      RSSHandler handler = new RSSHandler();      reader.setContentHandler(handler);      InputSource is = new InputSource(this.getClassLoader().getResourceAsStream("rssxml.xml"));//取得本地xml文件      reader.parse(is);      return handler.getFeed();    } catch (ParserConfigurationException e) {      // TODO Auto-generated catch block      e.printStackTrace();    } catch (SAXException e) {      // TODO Auto-generated catch block      e.printStackTrace();    } catch (IOException e) {      // TODO Auto-generated catch block      e.printStackTrace();    }    return null;  }  public void showList() {    ListView rsslistview = (ListView) findViewById(R.id.rssList);    TextView rsstitle = (TextView) findViewById(R.id.rsstitle);    if (feed == null) {      rsstitle.setText("訪問失敗...");      return;    }    SimpleAdapter adapter = new SimpleAdapter(this,        feed.getAllItemForListView(),        android.R.layout.simple_list_item_2, new String[] {            RSSItem.TITLE, RSSItem.PUBDATE }, new int[] {            android.R.id.text1, android.R.id.text2 });    rsslistview.setAdapter(adapter);  }}

展示下運行結果:

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 五家渠市| 翁牛特旗| 舞钢市| 盐源县| 江阴市| 贵阳市| 贡觉县| 白玉县| 大余县| 田阳县| 轮台县| 莎车县| 漯河市| 拜城县| 桑植县| 榆中县| 镇平县| 城口县| 商河县| 荔波县| 保山市| 隆德县| 宝山区| 嘉善县| 蒙城县| 牙克石市| 琼结县| 莱西市| 女性| 高陵县| 安阳县| 盐池县| 绥芬河市| 清涧县| 金山区| 惠来县| 思南县| 巴塘县| 宁津县| 无为县| 南汇区|