<%= request.getAttribute("content")==null?"
Web版RSS阅读器(五)——初步完成阅读功能
最后更新于:2022-04-01 20:40:22
上一篇博文《[Web版RSS阅读器(四)——定制自己的Rss解析库myrsslib4j](http://blog.csdn.net/xiaoxian8023/article/details/10048325)》中,已经分享给大家制作自己的rss解析库。稍微有点遗憾的是,它仅仅支持rss格式的博客。现在给大家分享一下我基于rome修改而成的另一款rss解析库——myrome,完美支持atom和rss 2种格式。
myrome.jar是在rome的基础上修改而来的,主要改动的地方是:([查看](http://note.youdao.com/share/?id=e9cdd75e55131fe6383e63d49fcc2440&type=note)[详细修改说明](http://note.youdao.com/share/?id=e9cdd75e55131fe6383e63d49fcc2440&type=note))
1. 修改GetAuthor()返回null
1. 修改getPublishedDate()返回null
1. 添加获取文章摘要的接口和方法
附下载地址:[http://pan.baidu.com/share/link?shareid=3563208157&uk=1259218556](http://pan.baidu.com/share/link?shareid=3563208157&uk=1259218556)
本篇主题是把myrome加入到RssReader中,修改界面,完成初步的访问和阅读的功能。具体实现的效果为:
1. 根据不同的订阅信息,加载对应的图标,从而一眼得知订阅的出处
1. 点击左侧的某个订阅,在中间的页面中显示出标题、时间和摘要列表,用水平线隔开
1. 点击某个摘要信息,在右侧内容区域,显示该文章的所有内容。
1. 双击摘要信息,则会用新窗口打开原文章地址。
等不及了吗?点[这里](http://mfxuan.free.800m.net/)或者**[](http://mfxuan.free.800m.net/)**[这里](http://test.free.800m.net/)抢先查看效果吧。
言归正传,接下来请大家跟随我初步成功的脚步:
下载myrome-1.0.jar,拷贝到WebRoot/WEB-INF/lib下。如果已经引用过rome-0.2.jar,要提前删除掉。在com.tgb.rssreader.manager包中新建RomeReadRss类,用来解析在线rss内容。
【RomeReadRss.java】
~~~
package com.tgb.rssreader.manager;
import java.net.URL;
import java.net.URLConnection;
import com.sun.syndication.feed.synd.SyndFeed;
import com.sun.syndication.io.SyndFeedInput;
import com.sun.syndication.io.XmlReader;
/**
* 解析Rss订阅信息
*
* @author Longxuan
*
*/
public class RomeReadRss {
/**
* 解析Rss订阅信息
*/
public SyndFeed parseRss(String rss) {
SyndFeed feed = null;
feed = null;
try {
URLConnection feedUrl = new URL(rss).openConnection();
// 由于服务器屏蔽java作为客户端访问rss,所以设置User-Agent
feedUrl.setRequestProperty("User-Agent",
"Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
// 读取Rss源
XmlReader reader = new XmlReader(feedUrl);
SyndFeedInput input = new SyndFeedInput();
// 得到SyndFeed对象,即得到Rss源里的所有信息
feed = input.build(reader);
} catch (Exception e) {
e.printStackTrace();
}
return feed;
}
}
~~~
修改left.jsp页的树形节点加载信息,根据不同的博客提供商,加载不同的图标。点击某节点后,将rss地址传递给servlet,去解析在线的rss。
【left.jsp】
~~~
<%@ page language="java" contentType="text/html; charset=GB18030"
pageEncoding="GB18030"%>
<%@ page import="com.tgb.rssreader.bean.*" %>
<%@ page import="java.util.*" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort()+path+"/";
%>
~~~
在com.tgb.rssreader.web包中新建一个RssServlet类,继承HttpServlet,实现doGet和doPost方法。它接收到有left.jsp传递过来的rss地址,调用RomeReadRss来解析rss内容。解析完毕后,转向middle.jsp,在中间这个网页中,显示解析的内容。
【RssServlet.java】
~~~
package com.tgb.rssreader.web;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.sun.syndication.feed.synd.SyndFeed;
import com.tgb.rssreader.manager.RomeReadRss;
/**
* 解析Rss信息资源Servlet
* @author Longxuan
*
*/
@SuppressWarnings("serial")
public class RssServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//获取rss地址
String rss = request.getParameter("rss");
//获取基于myrome的解析对象
RomeReadRss romeReadRss = RomeReadRss.getInstance();
//解析rss内容,存放到SyndFeed对象中
SyndFeed feed = romeReadRss.parseRss(rss);
//设置属性,用于传递SyndFeed对象
request.getSession().removeAttribute("feed");
request.getSession().setAttribute("feed", feed);
//转向middle.jsp
request.getRequestDispatcher("/middle.jsp").forward(request, response);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {
doGet(req, resp);
}
}
~~~
解析完毕后,开始修改middle.jsp。它接受到request中传递过来的SyndFeed对象,读取文章标题、发布时间及摘要信息,每篇文章都用横线隔开。未阅读过的显示黑色字体,阅读过后,显示灰色字体,鼠标指上去会变蓝色。点击文章摘要后,将该摘要的索引值传递过去;双击文章摘要信息,则会在新窗口中打开对应文章的实际连接。
【middle.jsp】
~~~
<%@ page language="java" contentType="text/html; charset=GB18030"
pageEncoding="GB18030"%>
<%@ page import="com.sun.syndication.feed.synd.*"%>
<%@page import="java.util.List"%>
<%@page session="true" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://"
+ request.getServerName() + ":" + request.getServerPort()
+ path + "/";
%>
~~~
当点击某篇文章标题时,将该文章的索引值传递到ArticleServlet中,在Session中找到对应的文章,把文章正文内容传递到content.jsp页面。所以在com.tgb.rssreader.web包中新建ArticleServlet类,继承HttpServlet,实现doGet和doPost方法。
【ArticleServlet.java】
~~~
package com.tgb.rssreader.web;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.sun.syndication.feed.synd.SyndContent;
import com.sun.syndication.feed.synd.SyndEntry;
import com.sun.syndication.feed.synd.SyndFeed;
/**
* 获取文章正文
* @author Longxuan
*
*/
@SuppressWarnings("serial")
public class ArticleServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//获取要查看的文章的索引值
int articleIndex = request.getParameter("articleIndex") == null? 0: Integer.parseInt( request.getParameter("articleIndex"));
//获取session中的变量
SyndFeed feed = (SyndFeed) request.getSession().getAttribute("feed");
SyndContent content = (SyndContent)((SyndEntry)feed.getEntries().get(articleIndex)).getContents().get(0);
request.setAttribute("content", content.getValue());
request.getRequestDispatcher("/content.jsp").forward(request, response);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doGet(req, resp);
}
}
~~~
在content.jsp中获取文章内容进行显示即可:
【content.jsp】
~~~
<%@ page language="java" contentType="text/html; charset=GB18030"
pageEncoding="GB18030"%>
<%@page import="com.sun.syndication.feed.synd.*"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://"
+ request.getServerName() + ":" + request.getServerPort()
+ path + "/";
%>
~~~
至此,Web版Rss阅读器阅读博客功能基本已经完工了,终于可以看到这款rss阅读器的样子了。当然需要优化的地方还很多。暂时打算告一段落,等过段时间再进行优化。基本的代码都已经写过了,~~不打算单独提供源码了。~~本来不打算提供源码了,因为按照步骤,差不多能整出来的。不过为了方便大家,刚刚还是把源码上传了,资源地址:
[http://download.csdn.net/detail/xiaoxian8023/8116737](http://download.csdn.net/detail/xiaoxian8023/8116737)
最后晒一下效果图吧:
[![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-18_56c53c293e265.jpg)](http://mfxuan.free.800m.net/)
[![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-18_56c53c294f0f5.jpg)](http://mfxuan.free.800m.net/)
**(点击图片在查看网站实例)**
**
**
如果您觉得做得不错,值得鼓励,就轻轻地【**顶一下**】吧
';
-
<%
//获取设置到session中的摘要信息
SyndFeed feed = (SyndFeed) request.getSession().getAttribute("feed");
if (feed == null)return;
//获取所有文章列表
List entriesList = feed.getEntries();
//循环加载文章摘要列表
for (int i = 0; i < entriesList.size(); i++) {
SyndEntry entry = (SyndEntry) entriesList.get(i);%>
- <%=entry.getTitle().trim()%> <%=entry.getPublishedDate().toLocaleString()%>
- <%=((SyndContent) entry.getContents().get(0)).getSummary(30)%>
<%}%>
Web版RSS阅读器(四)——定制自己的Rss解析库myrsslib4j
最后更新于:2022-04-01 20:40:20
在上篇博文《[Web版RSS阅读器(三)——解析在线Rss订阅](http://blog.csdn.net/xiaoxian8023/article/details/9811833)》中,已经提到了遇到的问题,这里再详细说一下。
在解析rss格式的订阅时,遇到的最主要的问题是,出现了“Server returned HTTP response code: 403 for URL: http://xxxxxx”的错误,[百度一下](http://www.baidu.com/s?wd=Server+returned+HTTP+response+code%3A+403+for+URL)就知道,这是在网站访问中很常见的一个错误,服务器理解客户的请求,但拒绝处理它。即拒绝访问!接着查资料,得知某些服务器(比如CSDN博客)拒绝java作为客户端进行对其的访问,所以在解析时,会抛异常。
不让访问怎么办,别怕,我们上有政策,下有对策。通过设置User-Agent来欺骗服务器,从而访问服务器。
~~~
connection.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)"); //用UA伪装访问连接对象
~~~
但是折腾了半天,发现只有修改rsslib4j.jar才能给连接对象设置UA。只好找源码修改一下了,N久之后,在Google Code上猎取到一个开源的项目newrsslib4j,它是在rsslib4j的基础上修改而来的,项目开源主页:[http://code.google.com/p/newrsslib4j/](http://code.google.com/p/newrsslib4j/)。满怀欣喜的下载下来,结果发现,依旧有403的问题。一狠心,自己来做一个rsslib,然后就checkout了newrsslib4j的源码,自己动手改动。
1. 修改403 forbidden问题。
修改org.gnu.stealthp.rsslib包中的RssParser类的setXmlResource()方法,给URLConnection对象,添加UA。
~~~
/**
* Set rss resource by URL
* @param ur the remote url
* @throws RSSException
*/
public void setXmlResource(URL ur) throws RSSException{
try{
URLConnection con = u.openConnection();
//-----------------------------
//添加时间:2013-08-14 21:00:17
//人员:@龙轩
//博客:http://blog.csdn.net/xiaoxian8023
//添加内容:由于服务器屏蔽java作为客户端访问rss,所以设置User-Agent
con.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
//-----------------------------
con.setReadTimeout(10000);
String charset = Charset.guess(ur);
is = new InputSource (new UnicodeReader(con.getInputStream(),charset));
if (con.getContentLength() == -1 && is == null){
this.fixZeroLength();
}
}catch(IOException e){
throw new RSSException("RSSParser::setXmlResource fails: "+e.getMessage());
}
}
~~~
修改org.mozilla.intl.chardet包中的Charset类的guess()方法,注释掉原来的InputStream对象,创建URLConnection,设置User-Agent,通过URLConnection对象创建InputStream :
~~~
//judge from url
public static String guess(URL url) throws IOException {
//-----------------------------
//修改时间:2013-08-14 21:00:17
//人员:@龙轩
//博客:http://blog.csdn.net/xiaoxian8023
//修改内容:注释InputStream,创建URLConnection,设置User-Agent,通过URLConnection对象创建InputStream
//InputStream in = url.openStream();
URLConnection con = url.openConnection();
con.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
InputStream in = con.getInputStream();
//-----------------------------
return guess(in);
}
~~~
2. 添加获取文章摘要的方法
测试以后,发现Rss格式的订阅,居然没有提供一个获取内容摘要的方法。所以,继续修改。修改org.gnu.stealthp.rsslib包中的RssObject类,添加一个getSummary()方法,用来获取内容摘要:
~~~
//-----------------------------------
//添加时间:2013-08-14 19:32:15
//人员:@龙轩
//添加内容:添加getSummary()方法,返回文章摘要信息
/**
* Get the element's summary
* @return the summary
*/
public String getSummary(){
String summary = getDescription();
if (summary.length() >= 300) {
summary = summary.substring(0, 300);
}
String regEx_html = "\\s|<[^>]+>|&\\w{1,5};"; // 定义HTML标签和特殊字符的正则表达式
Pattern pattern = Pattern.compile(regEx_html,Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(summary);
summary = matcher.replaceAll(""); // 过滤script标签
if (summary.length() >= 100) {
summary = summary.substring(0, 100);
}
summary = summary + "...";
return summary;
}
//添加结束-----------------------------------------------
~~~
3. 解决解析不完全问题
网易博客可以很好的解析出博客的link,language等节点,但是csdn、某些新闻资讯网站则不行。花了很长的时间去找问题,终于在不经意间,发现网易的博客节点的排列顺序与别的不一样,link,language等节点排在image节点上面的,而csdn则是在image的下面(如图),程序在解析时,先解析channel下的节点,写入到channel中,读取到image,则标记解析channel的变量为false,然后开始解析image节点下的内容。解析完毕以后,又要去解析channel节点下的link时,channel标记已经为false了,不能再继续解析,所以总是返回null。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-18_56c53c290a429.jpg)
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-18_56c53c291a6d4.jpg)
修改方案也很简单,就是所有标记解析channel为false的节点,在解析完毕该节点后,重新标记解析channel为true,这样就可以继续解析channel节点下的其他值 。具体修改操作:查看org.gnu.stealthp.rsslib包的RSSHandler类的startElement()方法,看看谁执行了 reading_chan = false; 这句代码。然后在endElement()方法中,重新设置 reading_chan = true; 即可:
~~~
/**
* Receive notification of the end of an element
* @param uri The Namespace URI, or the empty string if the element has no Namespace URI or if Namespace processing is not being performed.
* @param localName The local name (without prefix), or the empty string if Namespace processing is not being performed
* @param qName The qualified name (with prefix), or the empty string if qualified names are not available
*/
public void endElement(String uri,
String localName,
String qName){
String data = buff.toString().trim();
if (qName.equals(current_tag)){
data = buff.toString().trim();
buff = new StringBuffer();
}
if (reading_chan)
processChannel(qName,data);
if (reading_item)
processItem(qName,data);
if (reading_image)
processImage(qName,data);
if (reading_input)
processTextInput(qName,data);
if (tagIsEqual(qName,CHANNEL_TAG)){
reading_chan = false;
chan.setSyndicationModule(sy);
}
if (tagIsEqual(qName,ITEM_TAG)){
reading_item = false;
//-----------------------------------------
//添加时间:2013-08-14 21:00:17
//人员:@龙轩
//博客:http://blog.csdn.net/xiaoxian8023
//添加内容:重新允许解析channel
reading_chan = true;
//添加结束---------------------------------
chan.addItem(itm);
}
if (tagIsEqual(qName,IMAGE_TAG)){
reading_image = false;
//-----------------------------------------
//添加时间:2013-08-14 21:00:17
//人员:@龙轩
//博客:http://blog.csdn.net/xiaoxian8023
//添加内容:重新允许解析channel
reading_chan = true;
//添加结束---------------------------------
chan.setRSSImage(img);
}
if (tagIsEqual(qName,SEQ_TAG)){
reading_seq = false;
chan.addRSSSequence(seq);
}
if (tagIsEqual(qName,TEXTINPUT_TAG)){
reading_input = false;
//-----------------------------------------
//添加时间:2013-08-14 21:00:17
//人员:@龙轩
//博客:http://blog.csdn.net/xiaoxian8023
//添加内容:重新允许解析channel
reading_chan = true;
//添加结束---------------------------------
chan.setRSSTextInput(input);
}
}
~~~
至此,修改的就差不多了,打开一下org.javali.util.test包的RssNewsFetcher类,修改一下测试列表和方法:
~~~
package org.javali.util.test;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import org.gnu.stealthp.rsslib.RSSChannel;
import org.gnu.stealthp.rsslib.RSSException;
import org.gnu.stealthp.rsslib.RSSHandler;
import org.gnu.stealthp.rsslib.RSSItem;
import org.gnu.stealthp.rsslib.RSSParser;
public class RssNewsFetcher {
/**
* rss订阅列表
*/
private final static String[] rssArr = new String[] {
//"http://news.baidu.com/n?cmd=1&class=civilnews&tn=rss",
"http://xiaoxian100.blog.163.com/rss",
"http://blog.csdn.net/xiaoxian8023/rss/list"
};
/**
* 测试解析rss订阅
* @throws IOException
*/
public void testFetchRssNews() throws IOException {
for (int i = 0; i < rssArr.length; i++) {
try {
//获取rss订阅地址
URL url = new URL(rssArr[i]);
RSSHandler handler = new RSSHandler();
//解析rss
RSSParser.parseXmlFile(url, handler, false);
//获取Rss频道信息
RSSChannel ch = handler.getRSSChannel();
System.out.println("---------------------------------------------");
System.out.println("博客标题:" + ch.getTitle());
System.out.println("博客链接:" + ch.getLink());
System.out.println("博客描述:" + ch.getDescription());
System.out.println("博客语言:" + ch.getLanguage());
System.out.println("发布时间:" + ch.getPubDate());
System.out.println("图片地址:" +ch.getRSSImage().getUrl());
System.out.println("图片指向:" +ch.getRSSImage().getLink());
System.out.println("共有文章数目为:" + ch.getItems().size());
// for(i=0;i
';
Web版RSS阅读器(三)——解析在线Rss订阅
最后更新于:2022-04-01 20:40:18
上篇博客《[ Web版RSS阅读器(二)——使用dTree树形加载rss订阅分组列表](http://blog.csdn.net/xiaoxian8023/article/details/9745727)》已经写到读取rss订阅列表了,今天就说一下,当获取一条在线rss订阅的信息,怎么去解析它,从而获取文章或资讯。
首先说一下rss的版本。很多人都说rss,但是有相当一部分人,都不知道rss居然不只一种格式。我们常用的订阅格式有Rss和Atom 2种格式。Rss有版本从v0.9一直到现在的v2.0,Atom最新的版本则是1.0。
DeveloperWorks有一篇文章《[使用 RSS 和 Atom 实现新闻联合](http://www.ibm.com/developerworks/cn/web/wa-syndrssatom/index.html)》提及两者的相似点与不同点:
``> #### RSS 和 Atom 摘要的相似点
>
> 每个摘要文件实际上代表一个通道。它包含通道标题、链接、描述、作者等等。通道信息提供关于摘要的基本信息。通道信息之后是一些项。每项代表一篇可以从摘要阅读器阅读的真实的新闻或者文章。通常情况下,每项包含有标题、链接、更新时间和摘要信息。
> #### RSS 和 Atom 摘要的不同点
> 参考 [RSS 2.0 and Atom 1.0, Compared](http://www.intertwingly.net/wiki/pie/Rss20AndAtom10Compared),回顾 RSS 和 Atom 的不同点。
>
> RSS 和 Atom 具有相似的基于 XML 的格式。它们的基本结构是相同的,只在节点的表达式上有一点区别。
在Rss标准格式:
~~~
Lift Off News
http://liftoff.msfc.nasa.gov/
Liftoff to Space Exploration.
en-us
Tue, 10 Jun 2003 04:00:00 GMT
Tue, 10 Jun 2003 09:41:01 GMT
http://blogs.law.harvard.edu/tech/rss
Weblog Editor 2.0
5
-
Star City
http://liftoff.msfc.nasa.gov/news/2013/news-starcity.asp
How do Americans get ready to work with Russians aboard the
International Space Station? They take a crash course in culture, language
and protocol at Russia's Star City.
Tue, 03 Jun 2003 09:39:21 GMT
IT
bill
http://liftoff.msfc.nasa.gov/2003/06/03.html#item573
-
Space Exploration
http://liftoff.msfc.nasa.gov/
Sky watchers in Europe, Asia, and parts of Alaska and Canada
will experience a partial eclipse of the Sun on Saturday, May 31st.
Fri, 30 May 2003 11:06:42 GMT
http://liftoff.msfc.nasa.gov/2003/05/30.html#item572
~~~
Atom 1.0的格式:
~~~
Schema Web
2004-06-01T10:11:12Z
Uche Ogbuji
Welcome to Stanza Web
龙轩
http://www.cnblogs.com/longxuan/
2004-06-01T10:11:12Z
~~~
大部分新闻或博客网站都使用的是rss,当然Atom也占有部分市场。比如博客园就是用的Atom,而CSDN则用的是RSS。
了解了这些以后,就可以开始解析Rss了。
在网上找了一下开源的包,选了2款常用的都实验了一下,一个是Rome.jar,一个是rsslib4j.jar。二者的区别我就不多介绍了,有兴趣了可以去百度一下。rsslib4j 小巧,兼容性好,但是现在只支持解析rss 0.9x ,1.0 和 2.0,暂时对于atom无能为力。rsslib4j的开源主页:[http://sourceforge.net/projects/rsslib4j/](http://sourceforge.net/projects/rsslib4j/)。有什么需要的,可以在主页进行下载。
在WebRoot/lib中引用rsslib4j-0.2.jar,在src的com.tgb.rssreader.manager包中新建一个类Rsslib4jReadRss,贴出代码:
~~~
package com.tgb.rssreader.manager;
import java.net.URL;
import java.net.URLConnection;
import java.util.List;
import org.gnu.stealthp.rsslib.RSSChannel;
import org.gnu.stealthp.rsslib.RSSHandler;
import org.gnu.stealthp.rsslib.RSSImage;
import org.gnu.stealthp.rsslib.RSSItem;
import org.gnu.stealthp.rsslib.RSSParser;
public class Rsslib4jReadRss {
//这里定义一个在线的rss摘要的地址(对应我的网易博客)
public static final String remoteRSS="http://xiaoxian100.blog.163.com/rss";
public static void main(String[] args) throws Exception {
// 让RSSParser去解析在线的rss的url
RSSHandler remoteRSSHandler = new RSSHandler();
URL url = new URL(remoteRSS);
URLConnection feedUrl = url.openConnection();
RSSParser.parseXmlFile(feedUrl.getURL(), remoteRSSHandler, false);
// 取得rss元素的信息并且打印在控制台上
String remoteRSSInfo=Rsslib4jReadRss.getRSSInfo(remoteRSSHandler);
System.out.println("********我的网易博客的 rss信息如下**********");
System.out.println(remoteRSSInfo);
System.out.println("**************************");
}
public static String getRSSInfo(RSSHandler handler) {
StringBuffer rssInfo = new StringBuffer();
// 取得rss提要的频道信息(Channel)
RSSChannel channel = handler.getRSSChannel();
// Part1: 分离出rss频道的元信息
// (1)频道的标题
String titleInfo = channel.getTitle();
// (2)频道的链接信息
String linkInfo = channel.getLink();
// (3)频道的描述信息
String descriptionInfo = channel.getDescription();
// (4)频道使用的语言
String languageInfo = channel.getLanguage();
// (5)频道版权信息
String copyrightInfo = channel.getCopyright();
// (6)频道的generator的信息
String generatorInfo = channel.getGenerator();
// (7)频道的image信息
RSSImage channelImage = channel.getRSSImage();
String channelImageUrl = channelImage.getUrl();
rssInfo.append("频道标题: " + titleInfo + "\n");
rssInfo.append("频道相关Link信息: " + linkInfo + "\n");
rssInfo.append("频道描述信息: " + descriptionInfo + "\n");
rssInfo.append("频道使用的语言: " + languageInfo + "\n");
rssInfo.append("频道版权信息: " + copyrightInfo + "\n");
rssInfo.append("频道产生器信息: " + generatorInfo + "\n");
rssInfo.append("频道图片URL: " + channelImageUrl + "\n");
//Part2: 分离出rss频道的所有摘要(feed),这里用item表示
List channelItems = channel.getItems();
int itemSize = channelItems.size();
if (itemSize >= 1) {
rssInfo.append("\n");
rssInfo.append("一共有 " + itemSize + "个摘要在这个频道中");
rssInfo.append("\n");
for (int i = 0; i < itemSize; i++) {
int itemNo = i + 1;
RSSItem item = (RSSItem) channelItems.get(i);
rssInfo.append("\n");
rssInfo.append("摘要" + itemNo + ":");
// (1)摘要的作者
String itemAuthor = item.getAuthor();
// (2)摘要的标题
String itemTitle = item.getTitle();
// (3)摘要的描述
String itemDescription = item.getDescription();
// (4)摘要的链接
String itemLink = item.getLink();
// (5)摘要的发布日期
String itemPubDate = item.getPubDate();
rssInfo.append("作者: " + itemAuthor + "\n");
rssInfo.append("标题: " + itemTitle + "\n");
rssInfo.append("描述: " + itemDescription + "\n");
rssInfo.append("链接: " + itemLink + "\n");
rssInfo.append("发布日期: " + itemPubDate + "\n");
rssInfo.append("\n");
}
}
return rssInfo.toString();
}
}
~~~
由于文章太多,在Console中测试时,可能会看不到后面的效果,所以我只让程序读取了一个文章摘要(for循环次数修改为1),效果图如下:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-18_56c53c28e561f.jpg)
在解析网易博客时,还算勉强可以胜任,但是在解析CSDN博客时,就会报错"Server returned HTTP response code: 403 for URL: http://xxxxxx",这是因为CSDN博客,拒绝java作为客户端进行访问其服务器。而且在解析个别信息时,会出现null值。
那怎么办呀?别着急,下篇博文,大家跟我一起修改rsslib4j,做自己的rsslib4j。敬请期待!
';
不同点 | RSS 2.0 | Atom 1.0 |
部署 | RSS 2.0 得到广泛部署。 | Atom 1.0 还未得到广泛部署。 |
规范 | 哈佛大学拥有版权并冻结了 RSS 2.0 规范。 | Atompub 工作组(属于 IETF)就 Atom 1.0 规范达成一致意见,并在将来有可能重新修订。 |
所需内容 | RSS 2.0 包含所需的摘要级别的标题、链接和描述。它不需要在摘要中出现的任何单独项的字段。 | Atom 1.0 包含摘要和条目所需的标题(可以为空)、惟一标识和最后更新的时间戳。 |
有效负载(payload) | RSS 2.0 可以包含普通文本或者转义 HTML,但是不能分辨所提供的是两个中的哪一个。 | Atom 1.0 包含有效负载容器。 |
全部或者部分内容 | RSS 2.0 有一个 <description> 元素,可以包含条目的全部文本或者大纲。它没有用于标识内容是否完全的内置方法。 | Atom 1.0 提供单独的 <summary> 和 <content> 元素 。如果它是非文本的或者非本地的内容,出于可访问性的原因摘要将很好用。 |
自动发现 | RSS 2.0 用不同的方法实现自动发现。 | Atom 1.0 标准化自动发现。 |
提取和聚合 | RSS 2.0 只有一个可识别的形式:一个<rss> 文档。 | Atom 1.0 允许独立的 Atom Entry 文档,可以使用任何网络协议传输;例如,XMPP。Atom 也支持聚合摘要,其中,条目指向它们来自的摘要,前提是如果它们将被包含到其他摘要中。 |
Welcome to Stanza Web. Come back often to keep track of the best in modern poetry.
This site is powered by Atom
Web版RSS阅读器(二)——使用dTree树形加载rss订阅分组列表
最后更新于:2022-04-01 20:40:15
在上一边博客《[Web版RSS阅读器(一)——dom4j读取xml(opml)文件](http://blog.csdn.net/xiaoxian8023/article/details/9628751)》中已经讲过如何读取rss订阅文件了。这次就把订阅的文件读取到页面上,使用树形结构进行加载显示。
我使用的是mvc2来实现加载rss分组列表的。mvc2的流程如下:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-18_56c53c28b4f26.jpg)
由于这次是使用jsp来显示,所以把rss文件夹转移到WebRoot文件夹下了。对原来的【ReadXML.java】做了部分修改,重新贴出来。
~~~
package com.tgb.rssreader.manager;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import com.tgb.rssreader.bean.RssBean;
import com.tgb.rssreader.bean.RssConfigBean;
import com.tgb.rssreader.bean.RssTeamBean;
/**
* 读取xml文件
* @author Longxuan
*
*/
public class ReadXML {
// rss分组订阅列表
private List rssTeamBeanList = new ArrayList();
/**
* 读取rss文件列表
* @param directory
*/
public void ReadRssTeam(String directory) {
// rss文件列表配置信息实体
RssConfigMgr rssConfigMgr = new RssConfigMgr();
List list = rssConfigMgr.getRssConfig();
String errText = "";// 记录错误信息
// 循环读取rss文件列表
for (RssConfigBean rssConfig : list) {
// System.out.println(rssConfig.getName() + "----" +
// rssConfig.getPath());
try {
// 读取rss文件内容
//ReadRss(System.getProperty("user.dir")+ rssConfig.getPath());
ReadRss(directory + rssConfig.getPath());
} catch (Exception e) {
errText += e.getMessage();
}
}
//如果有异常信息,则汇总后抛出
if(!"".equals(errText)){
throw new RuntimeException(errText);
}
}
/**
* 读取ompl文件
*
* @param filePath
*/
private void ReadRss(String filePath) {
File file = new File(filePath);
if (!file.exists()) {
// System.out.println("找不到【" + filePath + "】文件");
// return;
throw new RuntimeException("找不到【" + filePath + "】文件");
}
try {
// 读取并解析XML文档
// SAXReader就是一个管道,用一个流的方式,把xml文件读出来
SAXReader reader = new SAXReader();
FileInputStream fis = new FileInputStream(file);
// 下面的是通过解析xml字符串的
Document doc = reader.read(fis);
// 获取根节点
Element rootElt = doc.getRootElement(); // 获取根节点
// System.out.println("根节点:" + rootElt.getName()); // 拿到根节点的名称
// 获取head/title节点
Element titleElt = (Element) rootElt.selectSingleNode("head/title");// 获取head节点下的子节点title
// 获取分组名称
String title = titleElt.getTextTrim();
// 获取body节点
Element bodyElt = (Element) rootElt.selectSingleNode("body");
// 获取body下的第一个outline节点
Element outlineElt = (Element) bodyElt.selectSingleNode("outline");
// 判断该outlineElt节点的属性数量,>2说明是详细博客订阅信息,否则则是分组信息。
if (outlineElt.attributes().size() > 2) { // 详细博客订阅信息
// 实例化 RSS分组实体
RssTeamBean rssTeamBean = new RssTeamBean();
// 获取body节点下的outline节点
Iterator> iter = bodyElt.elementIterator("outline");
// 输出分组名称
// System.out.println("分组名称:" + title);
// 记录分组名称
rssTeamBean.setTitle(title);
rssTeamBean.setText(title);
// 实例化订阅列表
List rssBeanList = new ArrayList();
// 获取详细博客订阅信息
ReadBlogsInfo(iter, rssBeanList);
// 设置订阅列表到分组中
rssTeamBean.setRssBeanList(rssBeanList);
// 添加分组到rss分组订阅列表
rssTeamBeanList.add(rssTeamBean);
} else { // 分组信息
// 获取body节点下的outline节点
Iterator> iter = bodyElt.elementIterator("outline");
while (iter.hasNext()) {
// 读取outline节点下的所有outline信息,每条信息都是一条订阅记录
Element TeamElt = (Element) iter.next();
// 实例化 RSS分组实体
RssTeamBean rssTeamBean = new RssTeamBean();
// 重新获取分组名称
title = TeamElt.attributeValue("title");
String text = TeamElt.attributeValue("text");
// System.out.println("分组title:" + title + " text:" +
// text);
// 记录分组名称和显示名称
rssTeamBean.setTitle(title);
rssTeamBean.setText(text);
// 实例化订阅列表
List rssBeanList = new ArrayList();
// 获取body节点下的outline节点
Iterator> iterRss = TeamElt.elementIterator("outline");
// 获取详细博客订阅信息
ReadBlogsInfo(iterRss, rssBeanList);
// 设置订阅列表到分组中
rssTeamBean.setRssBeanList(rssBeanList);
// 添加分组到rss分组订阅列表
rssTeamBeanList.add(rssTeamBean);
}
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (DocumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 读取当前组博客订阅信息
*
* @param iter
* 当前节点的子节点迭代器
* @param rssBeanList
* 订阅列表
*/
private void ReadBlogsInfo(Iterator> iter, List rssBeanList) {
// 遍历所有outline节点,每个节点都是一条订阅信息
while (iter.hasNext()) {
RssBean rssBean = new RssBean();
Element outlineElt = (Element) iter.next();
String htmlUrl = outlineElt.attributeValue("htmlUrl"); // 拿到当前节点的htmlUrl属性值
String xmlUrl = outlineElt.attributeValue("xmlUrl"); // 拿到当前节点的xmlUrl属性值
String version = outlineElt.attributeValue("version"); // 拿到当前节点的version属性值
String type = outlineElt.attributeValue("type"); // 拿到当前节点的type属性值
String outlineTitle = outlineElt.attributeValue("title"); // 拿到当前节点的title属性值
String outlineText = outlineElt.attributeValue("text"); // 拿到当前节点的text属性值
rssBean.setHtmlUrl(htmlUrl);
rssBean.setXmlUrl(xmlUrl);
rssBean.setVersion(version);
rssBean.setType(type);
rssBean.setTitle(outlineTitle);
rssBean.setText(outlineText);
rssBean.setText(outlineText);
// 将每条订阅信息,存放到订阅列表中
rssBeanList.add(rssBean);
}
}
/**
* 获取Rss分组订阅列表
*
* @return
*/
public List getRssTemBeanList() {
return rssTeamBeanList;
}
}
~~~
正题终于开始了:在src中新建包com.tgb.rssreader.web,添加RssTeamServlet,继承HttpServlet,实现doGet和doPost方法。它主要是用来调用com.tgb.rssreader.manager包下的ReadXML 类,以获取到分组信息,然后将其转发给left.jsp。源代码如下:
~~~
package com.tgb.rssreader.web;
import java.io.IOException;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.tgb.rssreader.bean.RssTeamBean;
import com.tgb.rssreader.manager.ReadXML;
/**
* 加载Rss分组
* @author Longxuan
*
*/
@SuppressWarnings("serial")
public class RssTeamServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//获取web项目的根目录的实际目录
String path = this.getServletConfig().getServletContext().getRealPath("/");
ReadXML readXML = new ReadXML();
//读取目录下的rss文件夹中的所有opml文件
//将所有分组信息保存在一个List中,
//将每个分组下的所有订阅信息,保存在该RssTeamBean中的一个List中
readXML.ReadRssTeam(path);
//获取装有所有分组信息的列表
List rssTemBeanList = readXML.getRssTemBeanList();
//将所有分组信息保存在request的属性rssTemBeanList中
request.setAttribute("rssTemBeanList", rssTemBeanList);
//转发request
request.getRequestDispatcher("/left.jsp").forward(request, response);
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
}
~~~
最后一步就是在界面上动工了。界面是自己先简单的做了个html的模版,已上传至[百度网盘](http://pan.baidu.com/share/link?shareid=2484310135&uk=1259218556)。布局使用frameset分割成3列,树形结构的Rss分组信息左侧,即left.jsp。中间的为某个rss订阅地址的文章列表,名为middle.jsp,右侧则是显示文章的地方,名为content.jsp。
现在先做成这样一个效果:左侧的left.jsp页,使用dTree的树形结构加载rss分组信息。点击一个订阅信息节点,在右侧显示出来对应的订阅内容。修改的是left.jsp,贴出源码:
~~~
<%@ page language="java" contentType="text/html; charset=GB18030"
pageEncoding="GB18030"%>
<%@ page import="com.tgb.rssreader.bean.*" %>
<%@ page import="java.util.*" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort()+path+"/";
%>
~~~
暂时的效果图如下:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-18_56c53c28cb0a5.jpg)
至此,读取rss分组已经完成了。接下来的博文中,会给大家解说一下rss版本以及解析在线的rss订阅。敬请期待。
';
不打算使用特殊的控件进行树型显示,也不想自己写了,想省劲些,就在 网上找了一个js树形脚本——dTree。dTree是一个易于使用的JavaScript树形 菜单控件。支持无限分级,可以在同一个页面中放置多个dTree,可以为每个 节点指定不同的图标。 主页:http://destroydrop.com/javascripts/tree/default.html |
Web版RSS阅读器(一)——dom4j读取xml(opml)文件
最后更新于:2022-04-01 20:40:13
接触java不久,偶有收获,最近想做一个web版RSS阅读器来锻炼一下。手头有几个从不同版本的foxmail中导出的opml文件,大家应该都知道,opml文件就是xml格式的。那么就先从这里入手,练习一下使用dom4j读取xml文件。
在java程序设计中,尤其是java web开发程序,xml应用频率超高。Spring、Hibernate、Struts等各种web 框架,MyEclipse、Oracle等IDE,也都主要依托xml。可以说xml对于系统的配置,有着至关重要的作用。而这些也同时增强了系统的灵活性。
先说一下思路:
新建一个java web项目,不过暂时没有使用jsp,servlet。本文只是使用自带的调试器,先进行测试读取xml。接下来的博文中,会带大家一起显示在已经优化的界面中,并提供大部分的rss阅读器的功能。
由于从不同版本的foxmail中导出,文件格式稍有不同,主要分歧是在订阅分组功能上。有的版本导出来的分组信息是在head/title内容中,body/outline则放的是全部的订阅信息;有的导出来的分组信息则是在body/outline中title和text属性中,而详细的订阅信息则放在body/outline/outline中。
我想做的系统可以支持读取多个opml文件,所以需要一个rss文件列表配置文件【rss_config.xml】,对应一个实体:RssConfigBean.java,主要包含有opml文件路径信息;分组信息也需要单独出来,命名为【RssTeamBean.java】,包括title和text两个属性和一个订阅信息的列表。订阅信息肯定也是独立的,命名为【RssBean.java】,包括text、title、xmlUrl、htmlUrl、version、type六个属性。
首先通过读取rss_config.xml,拿到所有opml文件路径,然后循环读取opml,拿到分组信息及每个分组下的所有详细订阅信息,保存到实体中,以供调用显示。
光说不管用,直接上代码:
①. opml文件
【单分组foxmail6.5.opml】
~~~
六期新博客地址
~~~
【多分组foxmail7.opml】
~~~
Subscription in Foxmail
~~~
②. 在src中新建rss文件列表配置文件
【rss_config.xml】
~~~
单分组foxmail6.5
\rss\单分组foxmail6.5.opml
多分组foxmail7
\rss\多分组foxmail7.opml
~~~
③. 新建包com.tgb.rssreader.bean,添加3个java文件:
【RssBean.java】详细订阅信息
~~~
package com.tgb.rssreader.bean;
/**
* 详细订阅信息
* @author Longxuan
*
*/
public class RssBean {
/**
* 显示名称
*/
private String text;
/**
* 标题
*/
private String title;
/**
* rss订阅地址
*/
private String htmlUrl;
/**
* rss订阅地址
*/
private String xmlUrl;
/**
* 版本
*/
private String version;
/**
* 类型
*/
private String type;
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getHtmlUrl() {
return htmlUrl;
}
public void setHtmlUrl(String htmlUrl) {
this.htmlUrl = htmlUrl;
}
public String getXmlUrl() {
return xmlUrl;
}
public void setXmlUrl(String xmlUrl) {
this.xmlUrl = xmlUrl;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
~~~
【RssConfigBean.java】 rss配置信息
~~~
package com.tgb.rssreader.bean;
/**
* rss配置信息
* @author Longxuan
*
*/
public class RssConfigBean {
/**
* 分组名称
*/
private String name;
/**
* 路径
*/
private String path;
public String getPath() {
return path;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setPath(String path) {
this.path = path;
}
}
~~~
【RssTeamBean.java】rss分组信息
~~~
package com.tgb.rssreader.bean;
import java.util.List;
/**
* rss分组信息
* @author Longxuan
*
*/
public class RssTeamBean {
/**
* 分组标题
*/
private String title;
/**
* 分组名称
*/
private String text;
private List rssBeanList ;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public List getRssBeanList() {
return rssBeanList;
}
public void setRssBeanList(List rssBeanList) {
this.rssBeanList = rssBeanList;
}
}
~~~
④. 新建包com.tgb.rssreader.manager,添加2个文件:
【RssConfigMgr.java】rss文件列表配置管理器
~~~
package com.tgb.rssreader.manager;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import com.tgb.rssreader.bean.RssConfigBean;
/**
* rss文件列表配置管理器
* @author Longxuan
*
*/
public class RssConfigMgr {
/**
* 读取rss文件列表配置信息
* @return
*/
public List getRssConfig() {
List list = new ArrayList();
RssConfigBean rssConfigBean = null;
InputStream is = Thread.currentThread().getContextClassLoader()
.getResourceAsStream("rss_config.xml");
if (is == null) {
//System.out.println("找不到该文件");
//return null;
throw new RuntimeException("找不到rss_config.xml文件");
}
try {
// 读取并解析XML文档
// SAXReader就是一个管道,用一个流的方式,把xml文件读出来
SAXReader reader = new SAXReader();
// 下面的是通过解析xml字符串的
Document doc = reader.read(is);
Element rootElt = doc.getRootElement(); // 获取根节点
//System.out.println("根节点:" + rootElt.getName()); // 拿到根节点的名称
Iterator> iter = rootElt.elementIterator("rss-list"); // 获取根节点下的子节点rss-list
// 遍历rss-list节点
while (iter.hasNext()) {
Element recordEle = (Element) iter.next();
String name = recordEle.elementTextTrim("rss-name"); // 拿到rss-list节点下的子节点name值
//System.out.println("name:" + name);
String path = recordEle.elementTextTrim("rss-path"); // 拿到rss-list节点下的子节点path值
//System.out.println("path:" + path);
rssConfigBean = new RssConfigBean();
//保存到rssConfigBean中
rssConfigBean.setName(name);
rssConfigBean.setPath(path);
//保存到list中
list.add(rssConfigBean);
}
} catch (DocumentException e) {
e.printStackTrace();
}
return list;
}
}
~~~
【ReadXML.java】读取xml文件
~~~
package com.tgb.rssreader.manager;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import com.tgb.rssreader.bean.RssBean;
import com.tgb.rssreader.bean.RssConfigBean;
import com.tgb.rssreader.bean.RssTeamBean;
/**
* 读取xml文件
* @author Longxuan
*
*/
public class ReadXML {
// rss分组订阅列表
private List rssTeamBeanList = new ArrayList();
/**
* 读取rss文件列表
*/
public void ReadRss() {
// rss文件列表配置信息实体
RssConfigMgr rssConfigMgr = new RssConfigMgr();
List list = rssConfigMgr.getRssConfig();
String errText = "";// 记录错误信息
// 循环读取rss文件列表
for (RssConfigBean rssConfig : list) {
// System.out.println(rssConfig.getName() + "----" +
// rssConfig.getPath());
try {
// 读取rss文件内容
ReadRss(System.getProperty("user.dir")+ rssConfig.getPath());
} catch (Exception e) {
errText += e.getMessage();
}
}
}
/**
* 读取ompl文件
*
* @param filePath
*/
private void ReadRss(String filePath) {
File file = new File(filePath);
if (!file.exists()) {
// System.out.println("找不到【" + filePath + "】文件");
// return;
throw new RuntimeException("找不到【" + filePath + "】文件");
}
try {
// 读取并解析XML文档
// SAXReader就是一个管道,用一个流的方式,把xml文件读出来
SAXReader reader = new SAXReader();
FileInputStream fis = new FileInputStream(file);
// 下面的是通过解析xml字符串的
Document doc = reader.read(fis);
// 获取根节点
Element rootElt = doc.getRootElement(); // 获取根节点
// System.out.println("根节点:" + rootElt.getName()); // 拿到根节点的名称
// 获取head/title节点
Element titleElt = (Element) rootElt.selectSingleNode("head/title");// 获取head节点下的子节点title
// 获取分组名称
String title = titleElt.getTextTrim();
// 获取body节点
Element bodyElt = (Element) rootElt.selectSingleNode("body");
// 获取body下的第一个outline节点
Element outlineElt = (Element) bodyElt.selectSingleNode("outline");
// 判断该outlineElt节点的属性数量,>2说明是详细博客订阅信息,否则则是分组信息。
if (outlineElt.attributes().size() > 2) { // 详细博客订阅信息
// 实例化 RSS分组实体
RssTeamBean rssTeamBean = new RssTeamBean();
// 获取body节点下的outline节点
Iterator> iter = bodyElt.elementIterator("outline");
// 输出分组名称
// System.out.println("分组名称:" + title);
// 记录分组名称
rssTeamBean.setTitle(title);
rssTeamBean.setText(title);
// 实例化订阅列表
List rssBeanList = new ArrayList();
// 获取详细博客订阅信息
ReadBlogsInfo(iter, rssBeanList);
// 设置订阅列表到分组中
rssTeamBean.setRssBeanList(rssBeanList);
// 添加分组到rss分组订阅列表
rssTeamBeanList.add(rssTeamBean);
} else { // 分组信息
// 获取body节点下的outline节点
Iterator> iter = bodyElt.elementIterator("outline");
while (iter.hasNext()) {
// 读取outline节点下的所有outline信息,每条信息都是一条订阅记录
Element TeamElt = (Element) iter.next();
// 实例化 RSS分组实体
RssTeamBean rssTeamBean = new RssTeamBean();
// 重新获取分组名称
title = TeamElt.attributeValue("title");
String text = TeamElt.attributeValue("text");
// System.out.println("分组title:" + title + " text:" +
// text);
// 记录分组名称和显示名称
rssTeamBean.setTitle(title);
rssTeamBean.setText(text);
// 实例化订阅列表
List rssBeanList = new ArrayList();
// 获取body节点下的outline节点
Iterator> iterRss = TeamElt.elementIterator("outline");
// 获取详细博客订阅信息
ReadBlogsInfo(iterRss, rssBeanList);
// 设置订阅列表到分组中
rssTeamBean.setRssBeanList(rssBeanList);
// 添加分组到rss分组订阅列表
rssTeamBeanList.add(rssTeamBean);
}
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (DocumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 读取当前组博客订阅信息
*
* @param iter
* 当前节点的子节点迭代器
* @param rssBeanList
* 订阅列表
*/
private void ReadBlogsInfo(Iterator> iter, List rssBeanList) {
// 遍历所有outline节点,每个节点都是一条订阅信息
while (iter.hasNext()) {
RssBean rssBean = new RssBean();
Element outlineElt = (Element) iter.next();
String htmlUrl = outlineElt.attributeValue("htmlUrl"); // 拿到当前节点的htmlUrl属性值
String xmlUrl = outlineElt.attributeValue("xmlUrl"); // 拿到当前节点的xmlUrl属性值
String version = outlineElt.attributeValue("version"); // 拿到当前节点的version属性值
String type = outlineElt.attributeValue("type"); // 拿到当前节点的type属性值
String outlineTitle = outlineElt.attributeValue("title"); // 拿到当前节点的title属性值
String outlineText = outlineElt.attributeValue("text"); // 拿到当前节点的text属性值
// System.out.print(" ");
rssBean.setHtmlUrl(htmlUrl);
rssBean.setXmlUrl(xmlUrl);
rssBean.setVersion(version);
rssBean.setType(type);
rssBean.setTitle(outlineTitle);
rssBean.setText(outlineText);
rssBean.setText(outlineText);
// 将每条订阅信息,存放到订阅列表中
rssBeanList.add(rssBean);
}
}
/**
* 获取Rss分组订阅列表
*
* @return
*/
public List getRssTemBeanList() {
return rssTeamBeanList;
}
public static void main(String[] args) {
ReadXML readXML = new ReadXML();
readXML.ReadRss();
List rssTemBeanList = readXML.getRssTemBeanList();
for (RssTeamBean rssTeamBean : rssTemBeanList) {
System.out.println("【分组title:" + rssTeamBean.getTitle() + " text:"+ rssTeamBean.getText()+"】");
for (RssBean rssBean : rssTeamBean.getRssBeanList()) {
System.out.print(" ");
}
System.out.println("-------------------------------------------------");
}
}
}
~~~
由于没有使用jsp进行显示,所以要想看效果,直接右键main函数,选择“Run As”-》“1 Java Application” ,进行测试。这里给出效果图:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-02-18_56c53c28933c4.jpg)
已经可以完全读取了。不论是单组旧版的,还是多分组新版导出来的opml文件,都可以正常读取。接下来的博文中,会写怎么把结果读取到jsp,会使用树结构来显示。后续版本会加上添加,删除,修改,移动订阅信息及复制订阅信息到组。同时也提供导入,导出功能。这些都会出现在后续博客中。尽请期待。
';
前言
最后更新于:2022-04-01 20:40:11
> 原文出处:[Web版Rss阅读器](http://blog.csdn.net/column/details/rssreader.html)
作者:[崔成龙](http://blog.csdn.net/xiaoxian8023)
**本系列文章经作者授权在看云整理发布,未经作者允许,请勿转载!**
# Web版Rss阅读器
> 从设计开始到基本功能实现,练习java web的简单入门的范例。
';