Informaを使ってRSSを処理してみる。

 RSS等を処理するライブラリ「Informa」を使って、RSSを解析してみる。
 解析するRSSは、ライブドアのWeather Hacksとし、RSSフィード一覧から全国の地点定義表を取得し、それから全国142箇所の天気予報を取得する。
 なお、地点定義表の解析は普通のDOMで解析した。

ソースコード

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Image;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import de.nava.informa.core.ChannelIF;
import de.nava.informa.core.ItemIF;
import de.nava.informa.core.ParseException;
import de.nava.informa.impl.basic.ChannelBuilder;
import de.nava.informa.parsers.FeedParser;

public class RssPanel extends JPanel{
	
	private static final long serialVersionUID = 1L;
	private DefaultTableModel model;
	private Map<String,ImageIcon> icons;
	
	public RssPanel(){
		super(new BorderLayout());
		JTable table=new JTable();
		super.add(new JScrollPane(table),BorderLayout.CENTER);
		model=new DefaultTableModel(){
			private static final long serialVersionUID = 1L;
			@Override
			public boolean isCellEditable(int row, int column) {
				return false;
			}
		};
		model.setRowCount(0);
		model.setColumnCount(3);
		model.setColumnIdentifiers(new String[]{"都市名","予報","URL"});
		table.setModel(model);
		table.setRowHeight(34);
		table.getColumnModel().getColumn(0).setMaxWidth(80);
		table.getColumnModel().getColumn(1).setMaxWidth(70);
		table.setDefaultRenderer(Object.class, new DefaultTableCellRenderer(){
			private static final long serialVersionUID = 1L;
			@Override
			public Component getTableCellRendererComponent(
			 JTable arg0, Object arg1, boolean arg2, boolean arg3,
						 int arg4, int arg5) {
				if(arg1 instanceof ImageIcon){
					JLabel ll=new JLabel((ImageIcon)arg1);
					return ll;
				}else if(arg1 instanceof URL){
					return super.getTableCellRendererComponent(
			 			 arg0, arg1, arg2, arg3, arg4, arg5);
				}else{
					return super.getTableCellRendererComponent(
			 			 arg0, arg1, arg2, arg3, arg4, arg5);
				}
			}
			
		});
		
		icons=new HashMap<String,ImageIcon>();
		Runnable r=new Runnable(){
			public void run(){
				List<Entry> urls=updateAreaCity();
				model.setRowCount(urls.size());
				updateModel(urls);
			}
		};
		new Thread(r).start();
	}
	
	private List<Entry> updateAreaCity(){
		try{
			List<Entry> ret=new ArrayList<Entry>();
			DocumentBuilderFactory dbf=DocumentBuilderFactory.newInstance();
			DocumentBuilder db=dbf.newDocumentBuilder();
			URL url = 
			    new URL("http://weather.livedoor.com/forecast/rss/forecastmap.xml");
			Document doc=db.parse(url.openStream());
			NodeList list=doc.getChildNodes();
			Node n=list.item(0);
			parse(n,ret);
			return ret;
		}catch(Exception e){
			e.printStackTrace();
			return null;
		}
	}
	
	private void parse(Node n,List<Entry> ret){
		NodeList list=n.getChildNodes();
		for(int i=0;i<list.getLength();i++){
			Node tmp=list.item(i);
			if(tmp.getNodeType()==3)continue;
			if(tmp.getNodeName().equals("city")){
				NamedNodeMap map=tmp.getAttributes();
				Entry e=new Entry();
				e.id=Integer.parseInt(map.getNamedItem("id").getNodeValue());
				e.name=map.getNamedItem("title").getNodeValue();
				e.url=map.getNamedItem("source").getNodeValue();
				ret.add(e);
			}
			if(tmp.hasChildNodes()){
				parse(tmp,ret);
			}
		}
	}
	
	private void updateModel(List<Entry> urls){
		for(Entry et : urls){
			try{
				URL url=new URL(et.url);
				ChannelIF channel = FeedParser.parse(new ChannelBuilder(), url);
				process(channel,et);
			}catch(MalformedURLException e){
				e.printStackTrace();
			}catch (ParseException e){
				e.printStackTrace();
			}catch (IOException e){
				e.printStackTrace();
			}
		}
	}
	
	private void process(ChannelIF channel,Entry e) throws 
				 	ParseException,IOException{
		Set<ItemIF> list=channel.getItems();
		for(ItemIF item : list){
			if(item.getTitle().contains("PR"))continue;
			URL url=item.getLink();
			String is=item.getElementValues("image", new String[]{"url"})[0];
			ImageIcon icon=icons.get(is);
			if(icon==null){
				URL u=new URL(is);
				Image im=ImageIO.read(u);
				icon=new ImageIcon(im);
			}
			model.setValueAt(e.name, e.id-1, 0);
			model.setValueAt(icon, e.id-1, 1);
			model.setValueAt(url, e.id-1, 2);
			break;
		}
	}
	
	private class Entry{
		int id;
		String name;
		String url;
	}
	
    public static void main(String[] args) {
    	JFrame f=new JFrame();
		try {
			UIManager.setLookAndFeel(
				"com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
			SwingUtilities.updateComponentTreeUI(f);
		}catch(Exception e){}
    	f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    	f.getContentPane().setLayout(new BorderLayout());
    	f.setSize(480, 320);
    	f.getContentPane().add(new RssPanel(),BorderLayout.CENTER);
    	f.setVisible(true);
	}
}

■実行結果
 実行結果は、以下のとおり。