`
445822357
  • 浏览: 736150 次
文章分类
社区版块
存档分类
最新评论

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所以官方英文博客RSS阅读器OPML文件

    花了点时间收集了Google所有的英文博客(截至目前为止,大约65个)的RSS地址,集中为OPML文件,可以上传到Google reader或者鲜果等阅读器集中阅读。

    我的RSS阅读列表 OPML格式

    收藏的很多RSS种子,可以导入到阅读器中,推荐使用Google阅读器

    opml:RSS阅读器中使用的OPML文件

    OPML 这是为 rss 阅读器存储 OPML(大纲处理器标记语言)文件的存储库,我个人非常喜欢它。如何将 OPML 文件导入 feedly 在,有“导入 OPML”按钮。 按下按钮并指定要导入的 OPML 文件。如何从 feedly 导出 OPML ...

    语音交互的RSS阅读器Beta

    注意:在使用导入导出功能时,请确保opml文件的正确性。 音量和语速调节 本程序还提供语音模式下的音量和语速调节功能,根据用户您的需要提供最佳的使用享受,具体调节方法如下: 音量调节:使用工具栏上的“音量...

    RSS OPML 列表 组件源码 VB实现集合

    实现RSS模型。 从网上抓取,支持OPML列表下载,且自动下载OPML列表中的资源,事件驱动方式。 本人测试,速度尚不错,下载10000个RSS集合,在常规速度(本人测试环境512K)需要10秒左右

    rss opml下载

    我 订阅的 rss 整理成 opml 导入到您的rss订阅器即可用

    ReadWorld (RSS聚合新闻阅读器)

    欢迎使用ReadWorldRSS阅读器 1 这个程序更改了我上回发布的《聚合新闻(RSS)阅读器》的一些错误。 2 新增了频道列表的拖放功能,及导入,导出(OPML)功能。 3 重新设计了一下界面 4 本程序是仿照《新郎点点通》...

    RSS Lib, opml

    从网上抓取,支持OPML列表下载,且自动下载OPML列表中的资源,事件驱动方式。 本人测试,速度尚不错,下载10000个RSS集合,在常规速度(本人测试环境512K)需要10秒左右下载完成全部解析完成,异步下载,不影响程序...

    新浪阅读器的二次开发

    缓存就是当选中treeview节点时,访问缓存(url)判断是否有xml数据,这面分两种情况,当无缓存时,我们在这面要第一次读取,读取完将xml数据写入缓存并记录当前的读取时间,显示xml数据。当有缓存时,判断时间是否...

    opml制作方法(模板及说明)

    opml可以通过文本文件格式打开。 163网易博客订阅,csdn博客订阅,使用博客链接制作成OPML,可以导入到foxmail中进行订阅,也可以通过导入到博客浏览器中进行订阅。

    opml-list:收集整理opml列表

    在做一个基于人工智能学习内容推荐的RSS阅读器,需要收集RSS源作为订阅源。 果 在一个每日更新所有的订阅源 生一个完整的opml作为阅读器的订阅源 体 github动作每日执行index.js, index.js中会下载收录的opml文件...

    c#实现对XML(OPML)文档动态生成树型菜单及对相应节点的操作维护

    利用c#实现对XML(OPML)文档的操作,根据OPML文档动态刷新出树型结构,然后对数型控件的操作将直接影响到相应的XML文档内容,感觉很实用

    opml_janitor:解析 OPML 文件,验证提要,并写入生成的 OPML

    它解析 XML,对于每个提要,它下载 RSS/Atom/等,验证提要在给定的时间范围内是否处于活动状态,并将结果写入一个新的 OPML XML 文档,其中仅包含好的提要。 安装 将此行添加到应用程序的 Gemfile 中: gem 'opml...

    xmind思维导图模板opml

    opml,ithoughts通用

    pbrr:相当基本的RSS阅读器

    PBRR-漂亮的基本RSS阅读器介绍构建一个简单的RSS阅读器,该阅读器从OPML文件中提取提要,并生成一个简单的html层次结构,并按站点和类别(如果OPML文件包含类别)对帖子进行分组。 无意建立任何复杂的网站,只是基于...

    xna.rar_RSS_XNA_atom_opml_聚合

    4.支持站点和时间分类,Tags浏览,单独页面浏览,并运用了ajax技术 5.支持搜索 6.支持导入和导出OPML 7.可显示favicon 8.具有多种主题样式,现有default,bxna两套主题 9.支持Rewrite启用 10.生成SiteMAP0.9 11....

    免费开源的 RSS 订阅器 QuiteRSS 0.19.3 中文绿色免费版.zip

    QuiteRss:免费开源新闻资讯RSS订阅工具是一个有用的基于Qt的新闻阅读器,支持便携式模式,可以帮助您监控和跟踪你最感兴趣的RSS源的最新消息,同时也支持便携版,方便用户在其他电脑上使用而不必担心数据丢失。...

    GoogleNewsRSS2OPML:Google News RSS as OPML

    该脚本试图通过生成文件来提供一种解决方法,该文件应可由任何* RSS阅读器使用当前URL(通过反复试验找到)导入。 它允许通过直接的命令行界面来自定义主题,位置和搜索查询以及版本/国家和语言设置: usage: ...

    Atom-Argotic,rss/atom/rsd/opml/apml/blogml/yahoo media/itunes的argotic联合框架的.net标准端口.zip

    Argotic是.NET开发人员可用的最强大和可扩展的Web内容联合框架之一,支持RSS、Atom、OPML、APML、RSD和BlogML。这个项目已经进入休眠期,但由于Argotic被用于制作Azure每周通讯和Power双周通讯,Endjin使之恢复了...

    RSS订阅源-前端充电宝.opml

    RSS订阅源-前端充电宝.opml

Global site tag (gtag.js) - Google Analytics