フィード(RSS)を検索(フィルタリング)するプログラムです。 DOMを利用しています。
指定された複数の文字列(検索語1, 検索語2, 検索語3, ...)のいずれも、title 要素か description 要素のどちらかに出現している item 要素を探し、その item 要素の内容(title, link, descriptionなど)を表示するプログラムです。
FeedViewer.java をベースにしているので、getElementsByTagName や XPath は利用していません。
import java.io.*; import java.net.*; import java.util.*; import javax.xml.parsers.*; import org.xml.sax.*; import org.w3c.dom.*; // Feed の内容を検索するプログラム (RSS 1.0/2.0対応) // FeedViewer.java ベースなので XPath 等は使用していない // 使い方: java FeedSearcher url word1 [word2 word3 ...] // (encoding は utf-8 固定) class Feed { private URL url; private String encoding; private Document document; private ArrayList<Item> itemList; public Feed() { url = null; encoding = "utf-8"; document = null; itemList = new ArrayList<Item>(); } public void setURL(String url) { try { this.url = new URL(url); } catch(IOException e) { System.err.println("間違ったURL: " + url); } } public void setEncoding(String encoding) { this.encoding = encoding; } /** URLで指示されたフィードを取得し DOM tree を構築 */ public void connect() { BufferedReader in = null; try { URLConnection connection = url.openConnection(); connection.connect(); InputStream inputStream = connection.getInputStream(); InputStreamReader reader = new InputStreamReader(inputStream, encoding); in = new BufferedReader(reader); } catch (IOException e) { System.err.println("接続エラー: " + e); System.exit(1); } try { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); document = builder.parse(new InputSource(in)); } catch (ParserConfigurationException e) { System.err.println("DocumentBuilderFactory生成エラー:" + e); } catch (SAXException e) { System.err.println("構文エラー:" + e); } catch (IOException e) { System.err.println("入出力エラー:" + e); } try { in.close(); } catch (IOException e) { System.err.println("接続終了エラー: " + e); } } /** Feed の内容を Item オブジェクトのリストとして返す */ public ArrayList<Item> getItemList() { try { // root要素 (rdf:RDF or rss) を得る Element rootElement = document.getDocumentElement(); String rootElementName = rootElement.getNodeName(); System.out.println("root element name: " + rootElementName); findItems(rootElement); } catch (DOMException e) { System.err.println("DOMエラー:" + e); } return itemList; } /** node の下位(子孫)から item 要素を探し Item オブジェクトを得る */ private void findItems(Node node) { for(Node current = node.getFirstChild(); current != null; current = current.getNextSibling()) { if(current.getNodeType() == Node.ELEMENT_NODE) { // そもそも要素か String nodeName = current.getNodeName(); if(nodeName.equals("item")) { // System.out.println("item 要素を発見!"); // item 要素から Item オブジェクトを得る Item item = getItem(current); // Item オブジェクトをリストに追加 // (ここで条件を満たすかチェックする方法もあり) itemList.add(item); } else { System.out.println(nodeName + " 要素をスキップ"); // channel, items などがスキップされる findItems(current); // さらに子ノードを見る (再帰) } } } } /** item 要素から Item オブジェクトを生成 */ private Item getItem(Node node) { String title = null; String link = null; String description = null; String date = null; String creator = null; for(Node current = node.getFirstChild(); current != null; current = current.getNextSibling()) { // 子ノードを先頭から if(current.getNodeType() == Node.ELEMENT_NODE) { // 要素だったら String nodeName = current.getNodeName(); if(nodeName.equals("title")) title = getContent(current); else if(nodeName.equals("link")) link = getContent(current); else if(nodeName.equals("description")) description = getContent(current); else if(nodeName.equals("dc:date") || nodeName.equals("pubDate")) date = getContent(current); else if(nodeName.equals("dc:creator")) creator = getContent(current); else if(nodeName.equals("guid") || nodeName.equals("category") || nodeName.startsWith("dc:") || nodeName.startsWith("rdf:") || nodeName.startsWith("dcq:")){ ; // 処理しない } else { ; // 処理しない } } // 要素 (Node.ELEMENT_NODE) でなかったら何もしない (改行など) } return new Item(title, link, description, date, creator); } /** title, link, description などの要素から内容を取り出す */ private String getContent(Node node) { String content = ""; node = node.getFirstChild(); // 子ノードがテキストのはず if(node.getNodeType() == Node.TEXT_NODE && node.getNodeValue().trim().length() != 0) content = node.getNodeValue(); else if(node.getNodeType() == Node.CDATA_SECTION_NODE) content = node.getNodeValue(); // HTMLタグなどを含む return content; } } /** 1つの item 要素に対応するオブジェクトを表すクラス */ class Item { private String title; private String link; private String description; private String date; private String creator; public Item (String title, String link, String description, String date, String creator) { this.title = title; this.link = link; this.description = description; this.date = date; this.creator = creator; } /** 単語群(配列の1番目から)をすべて含むかチェック */ public boolean containsAll(String[] words) { boolean containsAllWords = true; // 単語すべてが出現しているか否か // 初期値を true にしておいて、 // 出現していない単語が見つかったら false に for(int i = 1; i < words.length; i++) { // 各検索語iについて boolean appearing = false; // words[i] が出現しているか if(title.indexOf(words[i]) != -1) // title に出現? appearing = true; if(description.indexOf(words[i]) != -1) // description に出現? appearing = true; if(appearing == false) { // いずれの場所にも出現していない containsAllWords = false; // 出現していない単語があるよ break; // 1つでも出現していない単語が見つかったら中止 } } return containsAllWords; } /** 各属性を文字列に変換(表示に利用) */ public String toString() { String string = ""; if(title != null) string += "title: " + title + "\n"; if(link != null) string += "link: " + link + "\n"; if(description != null) string += "description: " + description + "\n"; if(date != null) string += "date: " + date + "\n"; if(creator != null) string += "creator: " + creator + "\n"; return string; } } class FeedSearcher { public static void main(String args[]) { Feed feed = new Feed(); feed.setURL(args[0]); feed.setEncoding("utf-8"); // 文字コードは utf-8 に固定 feed.connect(); ArrayList<Item> itemList = feed.getItemList(); // 表示 Iterator<Item> iterator = itemList.iterator(); while(iterator.hasNext()) { // いきなり表示するのではなく // System.out.print(iterator.next().toString()); Item item = iterator.next(); if(item.containsAll(args)) { System.out.print(item.toString()); System.out.println(); } } } }