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

最新文章

  1. 如何围绕企业战略,建设BI驾驶舱?
  2. java并发编程(一)可重入内置锁
  3. JQuery新闻滚动的实现方法(常用笔记1)
  4. 有7g和2g的砝码各一个,怎样称可以3次把140g东西分为50g和90g???????
  5. VS2010 打包问题汇总
  6. Fedora 下安装codeblocks
  7. springboot 注册服务注册中心(zk)的两种方式
  8. node.js简单搭建服务,访问本地站点文件
  9. 前端ps实用小技巧
  10. 学习 day4 html 盒子模型
  11. Sobel 边缘检测算子
  12. LeetCode(84): 柱状图中最大的矩形
  13. scipy.stats
  14. mac忘记操作密码
  15. 第二个spring冲刺第10天(及第二阶段总结)
  16. nohup php -f xx.php &amp;
  17. win7 、2008 提示Error 1606 Could Not Access Network Location %SystemDrive%/inetpub/wwwroot/ 的错误解决方法
  18. 透过面试题来说说Promise
  19. 中点Brehensam画圆算法
  20. deque!

热门文章

  1. JPA中的@MappedSuperclass
  2. mysql设置指定ip远程访问连接实例
  3. 可视化PK纯代码
  4. struts2中改变struts.xml默认路径
  5. UVa 1252 (状压DP + 记忆化搜索) Twenty Questions
  6. Android、iPhone和Java三个平台一致的加密工具
  7. apache开源项目 --Struts
  8. VirtualBox clonevdi文件和修改vdi的uuid
  9. POJ2402 Palindrome Numbers 回文数
  10. POJ:最长上升子序列