天天看點

[JAVA]SAX實作的簡易RSS閱讀器

RSS

RSS是簡易資訊聚合,使用者可以訂閱多個RSS源,進而在不打開網站頁面的情況下閱讀RSS輸出的網站内容。 一個RSS檔案就是一段規範的XML資料,如: http://sse.tongji.edu.cn/SSEMainRSS.aspx

SAX與DOM

SAX(Simple API for XML)是一個事件驅動的順序通路XML解析API。不同于DOM(Document Object Model)将整個XML文檔作為一個整體,SAX解析器按順序解析XML文檔的每個部分。 DOM解析器在任何處理開始之前,必須把整棵樹放進記憶體;而SAX事件驅動的本質讓其隻在需要時才将資料放入記憶體,并在處理完成後就丢棄。是以SAX在一些需求下所需的記憶體更少也更快。

以同濟大學SSE news為例: http://sse.tongji.edu.cn/SSEMainRSS.aspx

[JAVA]SAX實作的簡易RSS閱讀器
[JAVA]SAX實作的簡易RSS閱讀器

SAX解析此XML文檔時所觸發的事件序列為:

  • XML元素開始,name:channel
  • XML元素開始,name:title
  • XML文本節點,data:“同濟大學軟體學院通知RSS”
  • XML元素結束,name:title
  • XML元素開始,name:link
  • XML文本節點,data:“http://sse.tongji.edu.cn”
  • XML元素結束,name: link

RSS閱讀器Java實作

DefaultHandler是一個現有的Java類,包含在包org.xml.sax.helpers中,文檔如下: http://www.saxproject.org/apidoc/org/xml/sax/helpers/DefaultHandler.html

我們需要重寫該類的幾個方法來實作我們的RSS Reader,主要有以下5個:

void startDocument ()

Receive notification of the beginning of thedocument.

void endDocument ()  

Receive notification of the end of the document.

void startElement (Stringuri, String localName, String qName, Attributes attributes)      

         Receive notification of the start of an element.

         qName- The qualified name (with prefix), or the empty string if qualified names are not available.

void endElement (String uri,String localName, String qName)

      Receive notification of the end of an element.

void characters (char[] ch,intstart,int length)

       Receive notification of character data inside an element. 

還是以同濟大學SSE news為例: http://sse.tongji.edu.cn/SSEMainRSS.aspx

[JAVA]SAX實作的簡易RSS閱讀器

通過觀察我們可以發現,每一條新聞都包含在一對item标簽内,其中包含了description,link和pubDate。 是以我們建立一個RSSItem類來代表每一條新聞。

public class RSSItem {
		private String title;
		private String description;
		private String link;
		private String pubdate;
		//setters and getters…
    }
           

随後我們建立一個解析器RSSHandler,繼承DefaultHandler,

public class RSSHandler extends DefaultHandler{
    //…
}
           

然後重寫其中的方法。 開始解析文檔時,我們建立一個新的RSSItem對象來存儲第一條新聞。

public void startDocument () {  
        mRSSItem = new RSSItem();
	}
           

我們還需要告訴解析器遇到不同的XML元素該做怎樣的操作: 當遇到item标簽,代表我們開始通路新一條新聞,則需要重新執行個體化一個RSSItem對象。 當遇到title,description,link,pubDate标簽則表示我們仍在處理目前的這一條新聞,那麼設定一個currentState來标記目前增在處理的标簽。

public void startElement (String uri, String localName, String qName, Attributes attributes) {  
        //開始解析節點  
        if (qName.equals("channel")){  
            return ;  
        }     
        if (qName.equals("item")){  
            //當遇到一個item節點時,就執行個體化一個RSSItem對象  
            mRSSItem = new RSSItem();  
            return;  
        }  
        if (qName.equals("title")){  
            currentState = TITLE_STATE;  
            return ;  
        }
    //the same for description、link and pubDate…
}
           

當遇到文本節點,characters方法會被調用。我們所要做的是根據目前的currentState設定目前mRSSItem的相應屬性。

public void characters (char[] ch, int start, int length) {  
        String str = new String(ch, start, length);  
        switch(currentState){  
        case TITLE_STATE:  
            mRSSItem.setTitle(str);  
            currentState = 0;  
            break;
    //the same for description、link and pubDate…
}
           

當一條新聞解析完成時,我們需要将目前的mRSSItem存儲下來放到List中。

private List<RSSItem> mRSSItems;
public RSSHandler(List<RSSItem> mRSSItems){  
    	this.mRSSItems=mRSSItems;
     //…   
public void endElement (String uri, String localName, String qName) {  
        //節點解析結束
    	if(qName.equals("item"))
    		mRSSItems.add(mRSSItem);
    }  
}
           

至此,我們的RSSHandler已經基本完成了,解析來我們要獲得inputstream,并用RSSHandler來解析inputstream。

String url_str = "http://sse.tongji.edu.cn/SSEMainRSS.aspx";
	try {
		URL url = new URL(url_str);

		HttpURLConnection conn;
		conn = (HttpURLConnection) url.openConnection();
		conn.setRequestMethod("GET");
		conn.connect();
	
		InputStream in = conn.getInputStream();
				
		//建立工廠對象
		SAXParserFactory factory = SAXParserFactory.newInstance();  
		//産生SAX解析類對象
		SAXParser parser = factory.newSAXParser();  
		//産生XMLReader執行個體
		XMLReader xmlReader = parser.getXMLReader();
		//挂接事件處理對象到Reader上
		RSSHandler mRSSHandler = new RSSHandler(mRSSItems);
		xmlReader.setContentHandler(mRSSHandler); 
		//啟動串流解析
		xmlReader.parse(new InputSource(in)); 
	}catch (MalformedURLException e) {
			e.printStackTrace();
	}
           

此外,我們需要一個方法來去除擷取的資訊中的html元素:

public String getContent(String html){  
		String str = html.replaceAll("\\&[a-zA-Z]{1,10};","").replaceAll("<[^>]*>", "");
		str = str.replaceAll("[(/>)<]", "");
        return str;
    }  
           

最後,我用一個簡單的Swing界面來展示我們的成果,效果如下:

[JAVA]SAX實作的簡易RSS閱讀器

完整源碼下載下傳: http://pan.baidu.com/s/13UPX7

新址: http://www.limisky.com/109.html