接触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. JS调用客户端EXE

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  2. 给你一个承诺 - 玩转 AngularJS 的 Promise(转)

    在谈论Promise之前我们要了解一下一些额外的知识:我们知道JavaScript语言的执行环境是“单线程”,所谓单线程,就是一次只能够执行一个任务,如果有多个任务的话就要排队,前面一个任务完成后才可 ...

  3. vim - 查找替换

    :%s/\<key_word_replaced\>/word_you_want_to_say/g

  4. Java [Leetcode 172]Factorial Trailing Zeroes

    题目描述: Given an integer n, return the number of trailing zeroes in n!. Note: Your solution should be ...

  5. TCP/IP详解学习笔记(8)-DNS域名系统

    前面已经提到了访问一台机器要靠IP地址和MAC地址,其中,MAC地址可以通过ARP协议得到,所以这对用户是透明的,但是IP地址就不行,无论如何用户都需要用一个指定的IP来访问一台计算机,而IP地址又非 ...

  6. Oracle 课程二之Oracle数据库逻辑结构

    完成本课程的学习后,您应该能够: •数据库总体的逻辑结构 •深入理解数据库最小存储单元block •理解行迁移和行链接 •理解高水位线 •Drop.truncate.delete区别   1.数据库的 ...

  7. Delphi 使用串口模拟工具进行串口程序开发调试

      版权声明:本文为博主原创文章,如需转载请注明出处及作者. 本文由小李专栏原创,转载需注明出处:[http://blog.csdn.net/softwave/article/details/8907 ...

  8. JAVA和C/C++之间的相互调用。

    在一些Android应用的开发中,需要通过JNI和 Android NDK工具实现JAVA和C/C++之间的相互调用. Java Native Interface (JNI)标准是java平台的一部分 ...

  9. Extjs Ext.onReady的用法

    最近在学习Extjs,当然首先学习的肯定是从官网下载下来的example. 从学习上而言对于Extjs,我个人认同的是李林峰老师所言先从视图开始,搞一些所见即所得的东西. 废话有点多,对于Extjs而 ...

  10. 数据库(class0507)

    局部变量_先声明再赋值 声明局部变量 DECLARE @变量名 数据类型 DECLARE @name varchar(20) DECLARE @id int 赋值 SET @变量名 =值 --set用 ...