- 浏览: 736150 次
文章分类
最新评论
-
dfjjfxyl:
开源项目推荐网站:http://binlily.imwork. ...
JAVA开源项目 -
喵喵大神:
这类免费API还是挺多的,博客上也整理过:https://my ...
Web Api --智能Api接口
Web版RSS阅读器(一)——dom4j读取xml(opml)文件
接触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】
<?xml version="1.0"?> <opml version="1.1"> <head> <title>六期新博客地址</title> </head> <body> <outline text="丁成云" title="丁成云" type="rss" version="RSS" xmlUrl="http://blog.csdn.net/sundenskyqq/rss/list" htmlUrl="http://blog.csdn.net/sundenskyqq" description=""/> <outline text="韩正阳" title="韩正阳" type="rss" version="RSS" xmlUrl="http://blog.csdn.net/jiudihanbing/rss/list" htmlUrl="http://blog.csdn.net/jiudihanbing" description=""/> </body> </opml>
【多分组foxmail7.opml】
<?xml version="1.0" encoding="UTF-8"?> <opml version="1.0"> <head> <title>Subscription in Foxmail</title> </head> <body> <outline title="八期" text="八期"> <outline htmlUrl="http://blog.csdn.net/shan9liang" xmlUrl="http://blog.csdn.net/shan9liang/rss/list" version="RSS" type="rss" title="贾琳" text="贾琳的专栏"/> </outline> <outline title="随便看看" text="随便看看"> <outline htmlUrl="http://blog.csdn.net/blogdevteam" xmlUrl="http://blog.csdn.net/blogdevteam/rss/list" version="RSS" type="rss" title="CSDN 官方博客" text="CSDN 官方博客"/> <outline htmlUrl="http://blog.csdn.net/zhoufoxcn" xmlUrl="http://blog.csdn.net/zhoufoxcn/rss/list" version="RSS" type="rss" title="周公的专栏" text="周公的专栏"/> </outline> <outline title="提高班" text="提高班"> <outline htmlUrl="http://sxyandapp.blog.163.com" xmlUrl="http://sxyandapp.blog.163.com/rss" version="RSS" type="rss" title="石小永" text="石小永"/> <outline htmlUrl="http://blog.csdn.net/qiulongtianshi" xmlUrl="http://blog.csdn.net/qiulongtianshi/rss/list" version="RSS" type="rss" title="郭校林" text="郭校林"/> </outline> </body> </opml>
②. 在src中新建rss文件列表配置文件
【rss_config.xml】
<?xml version="1.0" encoding="UTF-8"?> <rss> <rss-list> <rss-name>单分组foxmail6.5</rss-name> <rss-path>\rss\单分组foxmail6.5.opml</rss-path> </rss-list> <rss-list> <rss-name>多分组foxmail7</rss-name> <rss-path>\rss\多分组foxmail7.opml</rss-path> </rss-list> </rss>
③. 新建包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<RssBean> 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<RssBean> getRssBeanList() { return rssBeanList; } public void setRssBeanList(List<RssBean> 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<RssConfigBean> getRssConfig() { List<RssConfigBean> list = new ArrayList<RssConfigBean>(); 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<RssTeamBean> rssTeamBeanList = new ArrayList<RssTeamBean>(); /** * 读取rss文件列表 */ public void ReadRss() { // rss文件列表配置信息实体 RssConfigMgr rssConfigMgr = new RssConfigMgr(); List<RssConfigBean> 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<RssBean> rssBeanList = new ArrayList<RssBean>(); // 获取详细博客订阅信息 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<RssBean> rssBeanList = new ArrayList<RssBean>(); // 获取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<RssBean> 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("<outline htmlUrl=\"" + htmlUrl + "\" "); // System.out.print("xmlUrl=\"" + xmlUrl + "\" "); // System.out.print("version=\"" + version + "\" "); // System.out.print("type=\"" + type + "\" "); // System.out.print("title=\"" + outlineTitle + "\" "); // System.out.println("text=\"" + outlineText + "\" />"); 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<RssTeamBean> getRssTemBeanList() { return rssTeamBeanList; } public static void main(String[] args) { ReadXML readXML = new ReadXML(); readXML.ReadRss(); List<RssTeamBean> rssTemBeanList = readXML.getRssTemBeanList(); for (RssTeamBean rssTeamBean : rssTemBeanList) { System.out.println("【分组title:" + rssTeamBean.getTitle() + " text:"+ rssTeamBean.getText()+"】"); for (RssBean rssBean : rssTeamBean.getRssBeanList()) { System.out.print("<outline htmlUrl=\"" + rssBean.getHtmlUrl() + "\" "); //System.out.print("xmlUrl=\"" + rssBean.getXmlUrl() + "\" "); System.out.print("version=\"" + rssBean.getVersion() + "\" "); System.out.print("type=\"" + rssBean.getType() + "\" "); System.out.print("title=\"" + rssBean.getTitle() + "\" "); System.out.println("text=\"" + rssBean.getText() + "\" />"); } System.out.println("-------------------------------------------------"); } } }
由于没有使用jsp进行显示,所以要想看效果,直接右键main函数,选择“Run As”-》“1 Java Application” ,进行测试。这里给出效果图:
已经可以完全读取了。不论是单组旧版的,还是多分组新版导出来的opml文件,都可以正常读取。接下来的博文中,会写怎么把结果读取到jsp,会使用树结构来显示。后续版本会加上添加,删除,修改,移动订阅信息及复制订阅信息到组。同时也提供导入,导出功能。这些都会出现在后续博客中。尽请期待。
相关推荐
花了点时间收集了Google所有的英文博客(截至目前为止,大约65个)的RSS地址,集中为OPML文件,可以上传到Google reader或者鲜果等阅读器集中阅读。
收藏的很多RSS种子,可以导入到阅读器中,推荐使用Google阅读器
OPML 这是为 rss 阅读器存储 OPML(大纲处理器标记语言)文件的存储库,我个人非常喜欢它。如何将 OPML 文件导入 feedly 在,有“导入 OPML”按钮。 按下按钮并指定要导入的 OPML 文件。如何从 feedly 导出 OPML ...
注意:在使用导入导出功能时,请确保opml文件的正确性。 音量和语速调节 本程序还提供语音模式下的音量和语速调节功能,根据用户您的需要提供最佳的使用享受,具体调节方法如下: 音量调节:使用工具栏上的“音量...
实现RSS模型。 从网上抓取,支持OPML列表下载,且自动下载OPML列表中的资源,事件驱动方式。 本人测试,速度尚不错,下载10000个RSS集合,在常规速度(本人测试环境512K)需要10秒左右
我 订阅的 rss 整理成 opml 导入到您的rss订阅器即可用
欢迎使用ReadWorldRSS阅读器 1 这个程序更改了我上回发布的《聚合新闻(RSS)阅读器》的一些错误。 2 新增了频道列表的拖放功能,及导入,导出(OPML)功能。 3 重新设计了一下界面 4 本程序是仿照《新郎点点通》...
从网上抓取,支持OPML列表下载,且自动下载OPML列表中的资源,事件驱动方式。 本人测试,速度尚不错,下载10000个RSS集合,在常规速度(本人测试环境512K)需要10秒左右下载完成全部解析完成,异步下载,不影响程序...
缓存就是当选中treeview节点时,访问缓存(url)判断是否有xml数据,这面分两种情况,当无缓存时,我们在这面要第一次读取,读取完将xml数据写入缓存并记录当前的读取时间,显示xml数据。当有缓存时,判断时间是否...
opml可以通过文本文件格式打开。 163网易博客订阅,csdn博客订阅,使用博客链接制作成OPML,可以导入到foxmail中进行订阅,也可以通过导入到博客浏览器中进行订阅。
在做一个基于人工智能学习内容推荐的RSS阅读器,需要收集RSS源作为订阅源。 果 在一个每日更新所有的订阅源 生一个完整的opml作为阅读器的订阅源 体 github动作每日执行index.js, index.js中会下载收录的opml文件...
利用c#实现对XML(OPML)文档的操作,根据OPML文档动态刷新出树型结构,然后对数型控件的操作将直接影响到相应的XML文档内容,感觉很实用
它解析 XML,对于每个提要,它下载 RSS/Atom/等,验证提要在给定的时间范围内是否处于活动状态,并将结果写入一个新的 OPML XML 文档,其中仅包含好的提要。 安装 将此行添加到应用程序的 Gemfile 中: gem 'opml...
opml,ithoughts通用
PBRR-漂亮的基本RSS阅读器介绍构建一个简单的RSS阅读器,该阅读器从OPML文件中提取提要,并生成一个简单的html层次结构,并按站点和类别(如果OPML文件包含类别)对帖子进行分组。 无意建立任何复杂的网站,只是基于...
4.支持站点和时间分类,Tags浏览,单独页面浏览,并运用了ajax技术 5.支持搜索 6.支持导入和导出OPML 7.可显示favicon 8.具有多种主题样式,现有default,bxna两套主题 9.支持Rewrite启用 10.生成SiteMAP0.9 11....
QuiteRss:免费开源新闻资讯RSS订阅工具是一个有用的基于Qt的新闻阅读器,支持便携式模式,可以帮助您监控和跟踪你最感兴趣的RSS源的最新消息,同时也支持便携版,方便用户在其他电脑上使用而不必担心数据丢失。...
该脚本试图通过生成文件来提供一种解决方法,该文件应可由任何* RSS阅读器使用当前URL(通过反复试验找到)导入。 它允许通过直接的命令行界面来自定义主题,位置和搜索查询以及版本/国家和语言设置: usage: ...
Argotic是.NET开发人员可用的最强大和可扩展的Web内容联合框架之一,支持RSS、Atom、OPML、APML、RSD和BlogML。这个项目已经进入休眠期,但由于Argotic被用于制作Azure每周通讯和Power双周通讯,Endjin使之恢复了...
RSS订阅源-前端充电宝.opml