1. 简介
1). SAX,全称Simple API for XML,是一种基于事件的解析器。
SAX采用事件驱动机制来解析XML文档。什么是事件驱动模式?它将XML文档转换成一系列的事件,由单独的事件处理器来决定如何处理。
每当SAX解析器发现文档开始、元素开始、文本、元素结束、文档结束等事件时,就会向外发送一次事件,而开发者则可以通过编写事件监听器处理这些事件,以此来获取XML文档里的信息。
工作原理: 就是对文档进行顺序扫描,当扫描到文档(document)开始与结束、元素(element)开始与结束、文档(document)结束等地方时通知事件处理函数,由事件处理函数做相应动作,然后继续同样的扫描,直至文档结束。
DOM也可以用来解析XML文件
DOM标准简单易用,但是它需要一次性地读取整个XML文档,而且在程序运行期间,整个DOM树常驻内存,导致系统开销过大。SAX解析方式占用内存小,处理速度更快。由于DOM一次性将整个XML文档全部读入内存,因此可以随机访问XML文档的每个元素。SAX采用顺序模式来依次读取XML文档,因此无法做到随机访问XML文档的任意元素
2). 实现过程
(一)第一步:新建一个工厂类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);
下面来介绍具体的实现:
1). 首先新建一个XML文件,如下:
<?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> </channel>
2). 一般解析一个XML文件都会对应到实体类中,因此为上面XML文件设计两个实体类,命名为:RSSItem, RSSFile,代码如下:
RSSItem代码如下:
1 package com.bing.file; 2 3 public class RSSItem { 4 5 public static final String CHANNEL = "channel"; 6 public static final String ITEM = "item"; 7 public static final String TITLE = "title"; 8 public static final String LINK = "link"; 9 public static final String CATAGORY = "category"; 10 public static final String DESCRIPTION = "description"; 11 public static final String PUBDATE = "pubDate"; 12 13 public static final int RSS_CHANNEL = 0; 14 public static final int RSS_TITLE = 1; 15 public static final int RSS_LINK = 2; 16 public static final int RSS_CATEGORY = 3; 17 public static final int RSS_DESCRIPTION = 4; 18 public static final int RSS_PUBDATE = 5; 19 20 private String title; 21 22 private String link; 23 24 private String catagory; 25 26 private String description; 27 28 private String pubDate; 29 30 public RSSItem(){ 31 32 } 33 34 public String getTitle(){ 35 return title; 36 } 37 38 public void setTitle(String title) { 39 this.title = title; 40 } 41 42 public String getLink() { 43 return link; 44 } 45 46 public void setLink(String link) { 47 this.link = link; 48 } 49 50 public String getCatagory() { 51 return catagory; 52 } 53 54 public void setCatagory(String catagory) { 55 this.catagory = catagory; 56 } 57 58 public String getDescription() { 59 return description; 60 } 61 62 public void setDescription(String description) { 63 this.description = description; 64 } 65 66 public String getPubDate() { 67 return pubDate; 68 } 69 70 public void setPubDate(String pubDate) { 71 this.pubDate = pubDate; 72 } 73 74 }
RSSFile代码如下:
1 package com.bing.file; 2 3 import java.util.ArrayList; 4 import java.util.HashMap; 5 6 import android.graphics.drawable.shapes.RoundRectShape; 7 8 public class RSSFile { 9 10 private ArrayList<RSSItem> rssFiles = new ArrayList<RSSItem>(); 11 12 public RSSFile(){ 13 14 } 15 16 public ArrayList<RSSItem> getRssFiles() { 17 return rssFiles; 18 } 19 20 public void setRssFiles(ArrayList<RSSItem> rssFiles) { 21 this.rssFiles = rssFiles; 22 } 23 24 //获取items数量 25 public int rssCount(){ 26 27 return rssFiles.size(); 28 } 29 30 //获取某一条Item信息 31 public RSSItem getRssItem(int position){ 32 33 return rssFiles.get(position); 34 } 35 36 //添加一条Item 37 public void addItem(RSSItem item){ 38 rssFiles.add(item); 39 } 40 41 /* 42 * 负责从RSSFeed类中生成列表所需要的数据 43 * return 44 */ 45 public ArrayList<HashMap<String, String>> getAllRecordList(){ 46 47 ArrayList<HashMap<String, String>> data = new ArrayList<HashMap<String,String>>(); 48 49 for(int i = 0; i < rssFiles.size(); i++){ 50 HashMap<String, String> item = new HashMap<String, String>(); 51 item.put(RSSItem.TITLE, rssFiles.get(i).getTitle()); 52 item.put(RSSItem.PUBDATE, rssFiles.get(i).getPubDate()); 53 data.add(item); 54 } 55 56 return data; 57 } 58 59 60 61 }
3). 完成实体类后,下一步就要写核心处理类,即:RSSHandler,它继承自DefaultHandler,需要重写startDocument,endDocument,startDocument,endElement,characters这五个方法
1 package com.bing.file; 2 3 import java.util.ArrayList; 4 5 import org.xml.sax.Attributes; 6 import org.xml.sax.SAXException; 7 import org.xml.sax.helpers.DefaultHandler; 8 9 public class RSSHandler extends DefaultHandler { 10 11 private RSSItem rssItem = null; 12 private RSSFile rssFile = null; 13 14 private ArrayList<RSSFile> rssList = null; 15 private int currentTAG; 16 17 18 public RSSHandler() { 19 // TODO Auto-generated constructor stub 20 rssItem = new RSSItem(); 21 rssFile = new RSSFile(); 22 } 23 24 25 public RSSFile getRSSFile(){ 26 return rssFile; 27 } 28 29 30 /** 31 * 当SAX解析器解析到XML文档开始时,会调用的方法 32 */ 33 @Override 34 public void startDocument() throws SAXException { 35 // TODO Auto-generated method stub 36 System.out.println("开始解析"); 37 } 38 39 40 /** 41 * 当SAX解析器解析到XML文档结束时,会调用的方法 42 */ 43 @Override 44 public void endDocument() throws SAXException { 45 // TODO Auto-generated method stub 46 System.out.println("解析完成"); 47 } 48 49 50 /** 51 * 当SAX解析器解析到某个元素开始时,会调用的方法 52 * 其中localName记录的是元素属性名 53 */ 54 @Override 55 public void startElement(String uri, String localName, String qName, 56 Attributes attributes) throws SAXException { 57 // TODO Auto-generated method stub 58 59 if(localName.equals(RSSItem.CHANNEL)){ 60 currentTAG = RSSItem.RSS_CHANNEL; 61 return; 62 } 63 if(localName.equals(RSSItem.ITEM)){ 64 rssItem = new RSSItem(); 65 return; 66 } 67 if(localName.equals(RSSItem.TITLE)){ 68 currentTAG = RSSItem.RSS_TITLE; 69 return; 70 } 71 if(localName.equals(RSSItem.LINK)){ 72 currentTAG = RSSItem.RSS_LINK; 73 return; 74 } 75 if(localName.equals(RSSItem.CATAGORY)){ 76 currentTAG = RSSItem.RSS_CATEGORY; 77 return; 78 } 79 if(localName.equals(RSSItem.DESCRIPTION)){ 80 currentTAG = RSSItem.RSS_DESCRIPTION; 81 return; 82 } 83 if(localName.equals(RSSItem.PUBDATE)){ 84 currentTAG = RSSItem.RSS_PUBDATE; 85 return; 86 } 87 currentTAG = RSSItem.RSS_CHANNEL; 88 89 System.out.println("处理标签"); 90 } 91 92 93 /** 94 * 当SAX解析器解析到某个元素结束时,会调用的方法 95 * 其中localName记录的是元素属性名 96 */ 97 @Override 98 public void endElement(String uri, String localName, String qName) 99 throws SAXException { 100 if(localName.equals("item")){ 101 rssFile.addItem(rssItem); 102 } 103 } 104 105 /** 106 * 当SAX解析器解析到某个属性值时,会调用的方法 107 * 其中参数ch记录了这个属性值的内容 108 */ 109 @Override 110 public void characters(char[] ch, int start, int length) 111 throws SAXException { 112 113 String content = new String(ch, start, length); 114 switch(currentTAG){ 115 case RSSItem.RSS_TITLE: 116 rssItem.setTitle(content); 117 currentTAG = RSSItem.RSS_CHANNEL; 118 break; 119 case RSSItem.RSS_LINK: 120 rssItem.setLink(content); 121 currentTAG = RSSItem.RSS_CHANNEL; 122 break; 123 case RSSItem.RSS_CATEGORY: 124 rssItem.setCatagory(content); 125 currentTAG = RSSItem.RSS_CHANNEL; 126 break; 127 case RSSItem.RSS_DESCRIPTION: 128 rssItem.setDescription(content); 129 currentTAG = RSSItem.RSS_CHANNEL; 130 break; 131 case RSSItem.RSS_PUBDATE: 132 rssItem.setPubDate(content); 133 currentTAG = RSSItem.RSS_CHANNEL; 134 break; 135 default: 136 return; 137 } 138 139 } 140 141 142 }
4).最后,在界面显示XML
main.xml布局如下,没有可说的
1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:paddingBottom="@dimen/activity_vertical_margin" 6 android:paddingLeft="@dimen/activity_horizontal_margin" 7 android:paddingRight="@dimen/activity_horizontal_margin" 8 android:paddingTop="@dimen/activity_vertical_margin" 9 tools:context="com.bing.saxtest.MainActivity" > 10 11 <ListView 12 android:id="@+id/android:rsslist" 13 android:layout_width="fill_parent" 14 android:layout_height="fill_parent" 15 /> 16 17 </RelativeLayout>
main类
1 package com.bing.saxtest; 2 3 import java.io.IOException; 4 import javax.xml.parsers.ParserConfigurationException; 5 import javax.xml.parsers.SAXParser; 6 import javax.xml.parsers.SAXParserFactory; 7 8 import org.xml.sax.InputSource; 9 import org.xml.sax.SAXException; 10 import org.xml.sax.XMLReader; 11 12 import android.app.Activity; 13 import android.os.Bundle; 14 import android.util.Log; 15 import android.widget.ListView; 16 import android.widget.SimpleAdapter; 17 18 import com.bing.file.RSSFile; 19 import com.bing.file.RSSHandler; 20 import com.bing.file.RSSItem; 21 22 23 public class MainActivity extends Activity { 24 25 private static final String TAG = "MainActivity"; 26 27 private static final String XMLPATH = "xml/test.xml"; 28 29 private ListView list; 30 31 private RSSHandler rssHandler; 32 33 private RSSFile rssFile = null; 34 35 @Override 36 protected void onCreate(Bundle savedInstanceState) { 37 super.onCreate(savedInstanceState); 38 setContentView(R.layout.activity_main); 39 40 initData(); 41 42 showList(); 43 44 } 45 46 private void initData(){ 47 48 SAXParserFactory factory = SAXParserFactory.newInstance(); 49 try { 50 SAXParser parser = factory.newSAXParser(); 51 XMLReader reader = parser.getXMLReader(); 52 53 rssHandler = new RSSHandler(); 54 reader.setContentHandler(rssHandler); 55 56 InputSource input = new InputSource(this.getResources().getAssets().open(XMLPATH)); 57 reader.parse(input); 58 59 rssFile = rssHandler.getRSSFile(); 60 61 } catch (ParserConfigurationException e) { 62 e.printStackTrace(); 63 } catch (SAXException e) { 64 e.printStackTrace(); 65 } catch (IOException e) { 66 e.printStackTrace(); 67 } 68 69 } 70 71 72 private void showList(){ 73 list = (ListView) findViewById(R.id.android_rsslist); 74 75 Log.i(TAG, rssFile.rssCount() + ""); 76 SimpleAdapter adapter = new SimpleAdapter(this, rssFile.getAllRecordList(), android.R.layout.simple_list_item_2, 77 new String[]{RSSItem.TITLE, RSSItem.PUBDATE}, new int[]{android.R.id.text1, android.R.id.text2} 78 ); 79 80 list.setAdapter(adapter); 81 82 } 83 84 85 86 }
5). 结果显示
参考文献:
1. http://www.cnblogs.com/felix-hua/archive/2012/01/10/2317404.html