• 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>
    ss单分组foxmail6.5.opml</rss-path>
    	</rss-list>
    	<rss-list>
    		<rss-name>多分组foxmail7</rss-name>
    		<rss-path>
    ss多分组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,会使用树结构来显示。后续版本会加上添加,删除,修改,移动订阅信息及复制订阅信息到组。同时也提供导入,导出功能。这些都会出现在后续博客中。尽请期待。


  • 相关阅读:
    Mybatis——逆向工程
    Mybatis——Spring整合
    Mybatis——缓存机制
    Mbatis——动态SQL
    Mybatis_映射文件配置
    Mybatis XML 配置文件
    渣渣小本求职复习之路每天一博客系列——数据结构与常用算法(2)
    渣渣小本求职复习之路每天一博客系列——数据结构与常用算法(1)
    渣渣小本求职复习之路每天一博客系列——数据库基础(MySQL)(5)
    渣渣小本求职复习之路每天一博客系列——数据库基础(MySQL)(4)
  • 原文地址:https://www.cnblogs.com/riskyer/p/3226219.html
Copyright © 2020-2023  润新知