接触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,会使用树结构来显示。后续版本会加上添加,删除,修改,移动订阅信息及复制订阅信息到组。同时也提供导入,导出功能。这些都会出现在后续博客中。尽请期待。

RSS阅读器(一)——dom4j读取xml(opml)文件的更多相关文章

  1. Web版RSS阅读器(二)——使用dTree树形加载rss订阅分组列表

    在上一边博客<Web版RSS阅读器(一)——dom4j读取xml(opml)文件>中已经讲过如何读取rss订阅文件了.这次就把订阅的文件读取到页面上,使用树形结构进行加载显示. 不打算使用 ...

  2. C#版简易RSS阅读器

    C#版简易RSS阅读器.由VB版修改完成,感谢aowind的技术支持! 源代码: using System; using System.Drawing; using System.Collection ...

  3. [UWP]涨姿势UWP源码——极简的RSS阅读器

    涨姿势UWP,一个开源的RSS阅读器,一个纯粹的项目,一个有道德的APP,一个脱离了低级趣味的作者,一些有益于人民的代码.骚年,还等什么,来涨点姿势吧! 该项目代码可能会引起部分人群的不适,敏感人群请 ...

  4. 网易新闻RSS阅读器

    首先需要分析网易RSS订阅中心的网页布局情况. 网易RSS订阅中心:http://www.163.com/rss/ 你会发现RSS文件由一个<channel>元素及其子元素组成,除了频道本 ...

  5. Web版RSS阅读器(三)——解析在线Rss订阅

    上篇博客<Web版RSS阅读器(二)——使用dTree树形加载rss订阅分组列表>已经写到读取rss订阅列表了,今天就说一下,当获取一条在线rss订阅的信息,怎么去解析它,从而获取文章或资 ...

  6. RSS阅读器

    RSS阅读器(Really Simple Syndication)是一种软件/程序,实质都是为了方便地读取RSS和Atom文档.大概就是实现了订阅式阅读,推送用户感兴趣的新闻,博客等(比如等某位博主更 ...

  7. RSS阅读器python实现概述

    这边简单说一下最近倒腾的RSS阅读器的小东东,RSS阅读器估计很多人用过或者自己动手实现过.首先wudagang0123多年前提供的一个示例:http://bbs.chinaunix.net/foru ...

  8. RSS阅读器&BT sync

    ①RSS阅读器? 答:RSS阅读器是一种软件或是说一个程序,这种软件可以自由读取RSS和Atom两种规范格式的文档,且这种读取RSS和Atom文档的软件有多个版本,由不同的人或公司开发,有着不同的名字 ...

  9. DOM4J读取XML文件

    最近在做DRP的项目,其中涉及到了读取配置文件,用到了DOM4J,由于是刚开始接触这种读取xml文件的技术,好奇心是难免的,于是在网上又找了一些资料,这里就结合找到的资料来谈一下读取xml文件的4中方 ...

随机推荐

  1. bzoj4044

    这题简直了………… 首先根据操作可知,我们肯定是先造出某个偶数长度的回文串,然后添加若干字符得到设回文串长为len[x] 则ans=min(n-len[x]+f[x]); 那么问题就是制造这个串的回文 ...

  2. Apache Struts2 s2-020补丁安全绕过漏洞

    CNVD-ID CNVD-2014-01552 发布时间 2014-03-11 危害级别 高 影响产品 Apache struts 2.0.0-2.3.16 BUGTRAQ ID 65999 CVE ...

  3. Vagrant工具

    Vagrant 是一款用来构建虚拟开发环境的工具,非常适合 php/python/ruby/java 这类语言开发 web 应用,“代码在我机子上运行没有问题”这种说辞将成为历史. 我们可以通过 Va ...

  4. qtcreator cannot find -lts

    /********************************************************************* * qtcreator cannot find -lts ...

  5. I.MX6 linux Qt 同时支持Touch、mouse

    /***************************************************************************** * I.MX6 linux Qt 同时支持 ...

  6. 物联网操作系统HelloX V1.78测试版正式发布

    经过HelloX开发团队近四个月的努力,在HelloX V1.77版本基础上,增加许多功能特性,并对V1.77版本的一些特性进行了进一步优化之后,正式形成HelloX V1.78测试版本,经相对充分的 ...

  7. python - pip 从已有的安装列表 安装

    已经安装好的机器:sudo pip freeze > install_list.list 需要安装的机器:sudo pip install -r install_list.list

  8. T-SQL查询进阶-10分钟理解游标

    转:http://www.cnblogs.com/CareySon/archive/2011/11/01/2231381.html 概述 游标是邪恶的! 在关系数据库中,我们对于查询的思考是面向集合的 ...

  9. 给定一个函数rand()能产生0到n-1之间的等概率随机数,问如何产生0到m-1之间等概率的随机数?

    题目:给定一个函数rand()能产生1到n之间的等概率随机数,问如何产生1到m之间等概率的随机数? 先把问题特殊化,例如原题变为给定一个函数rand5(),该函数可以随机生成1-5的整数,且生成概率一 ...

  10. POJ 1083 Moving Tables

    题意:一个建筑物里有400个房间,房间都在一层里,在一个走廊的两侧,如图,现在要搬n张桌子,告诉你每张桌子是从哪个屋搬到哪个屋,搬桌子的线路之间不可以有重叠,问最少搬几次. 解法:贪心.一开始觉得只要 ...