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
 
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中,文档如下:
 
我们需要重写该类的几个方法来实现我们的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
通过观察我们可以发现,每一条新闻都包含在一对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界面来展示我们的成果,效果如下:


完整源码下载:http://pan.baidu.com/s/13UPX7

posted @ 2017-01-20 16:49  atzuge  阅读(584)  评论(0编辑  收藏  举报