RSSリーダ(RSS1.0対応) -- CDATAセクションの値を取り出す

戻る
RSS1.0対応です。

import javax.xml.parsers.*;
import org.w3c.dom.*;
import java.io.*;
import java.util.*;

/**
* $Id: rss1_0.html,v 1.1 2009/06/22 16:12:24 kishi Exp kishi $
* @author KISHI Yasuhiro
*/

public class RSS1_0 {

    /** ドキュメントのルート要素 */
    private Element root;

    private RSSEntity channel = null;
    private RSSEntity image = null;
    private List<RSSEntity> itemList = null;

    public static void main( String[] args ) {

        if ( args.length != 1 ) {
            System.out.println( "usage: java -cp . RSS1_0 [URI|fileName]" );
            System.exit( -1 );
        }
        String source = args[ 0 ];

        try {

            /////////////////////////////////////////////////////
            // RSSリーダのインスタンス生成
            /////////////////////////////////////////////////////
            RSS1_0 reader = new RSS1_0( source );

            /////////////////////////////////////////////////////
            // ルート要素から再帰的に走査していく
            /////////////////////////////////////////////////////
            reader.traverse();

            // ダンプする
            reader.iterateAll();

        } catch ( Exception e ) {
            e.printStackTrace();
        }

    }

    public RSS1_0( String source ) throws Exception {
        init( source );
    }

    private void init( String source ) throws Exception {
        //------------------------------------------------------------------------------------
        // ドキュメントビルダーファクトリを生成
        //------------------------------------------------------------------------------------
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

        //------------------------------------------------------------------------------------
        // 【重要】 -- CDATAノードの取り出し方です --
        // このファクトリで作成されたパーサが CDATA ノードを Text ノードに変換し、
        // それを隣接 (存在する場合) Text ノードに追加するように指定します。
        // デフォルトでは、この値は false に設定されます。
        //------------------------------------------------------------------------------------
        factory.setCoalescing( true );

        //------------------------------------------------------------------------------------
        // ドキュメントビルダーを生成
        //------------------------------------------------------------------------------------
        DocumentBuilder builder = factory.newDocumentBuilder();

        //----------------------------------------------------------------
        // パースを実行してDocumentオブジェクトを取得
        //----------------------------------------------------------------
        Document doc = builder.parse( source );

        System.out.println( "【XMLのバージョン】" + doc.getXmlVersion() );
        System.out.println( "【文書のエンコーディング】" + doc.getXmlEncoding() );

        // ルート要素を取得(タグ名:rss)
        root = doc.getDocumentElement();

        System.out.println( "【ルート要素のタグ名】" + root.getTagName() );
        System.out.println( "【ルート要素の属性】" + root.getAttribute( "xmlns" ) );

        // --- ここまではXML文書を読むための共通処理

    }

    public void traverse() {
        // 子要素のリストを取得 -- getFirstChild()はNodeクラスが持つメソッドなのでキャストする
        Node childNode = ( ( Node ) root ).getFirstChild();

        while ( childNode != null ) {
            String nodeName = childNode.getNodeName();

            if ( "channel".equals( nodeName ) ) {
                // System.out.println( nodeName );
                parseChannel( childNode );
            }
            if ( "image".equals( nodeName ) ) {
                // System.out.println( nodeName );
                parseImage( childNode );
            }
            if ( "item".equals( nodeName ) ) {
                // System.out.println( nodeName );
                parseItem( childNode );
            }
            childNode = childNode.getNextSibling();
        }

    }

    /**
    * セットされた情報を全て列挙する
    */
    public void iterateAll() {

        if ( channel != null ) {
            System.out.println();
            System.out.println( "/** channel */" );
            channel.iterate();
        }

        if ( image != null ) {
            System.out.println();
            System.out.println( "/** image */" );
            image.iterate();
        }

        if ( itemList != null ) {
            Iterator iterator = itemList.iterator();
            while ( iterator.hasNext() ) {
                RSSEntity item = ( RSSEntity ) iterator.next();
                System.out.println();
                System.out.println( "/** item */" );

                item.iterate();
            }
        }
    }

    private void parseItem( Node node ) {
        if ( itemList == null ) {
            itemList = new LinkedList();
        }

        RSSEntity item = new RSSEntity();
        item.put( "rdf:about", ( ( Element ) node ).getAttribute( "rdf:about" ) );

        // 子要素のリストを取得
        Node childNode = node.getFirstChild();

        while ( childNode != null ) {
            String nodeName = childNode.getNodeName();

            // System.out.println( nodeName );
            if ( childNode.hasChildNodes() ) {
                if ( "link".equals( nodeName )
                        || "title".equals( nodeName )
                        || "description".equals( nodeName )
                        || "dc:subject".equals( nodeName )
                        || "dc:creation".equals( nodeName )
                        || "dc:date".equals( nodeName )
                        || "content:encoded".equals( nodeName )
                   ) {
                    item.put( nodeName, childNode.getFirstChild().getNodeValue() );
                }
            }

            childNode = childNode.getNextSibling();
        }

        itemList.add( item );
    }

    private void parseChannel( Node node ) {

        channel = new RSSEntity();

        channel.put( "rdf:about", ( ( Element ) node ).getAttribute( "rdf:about" ) );

        // 子要素のリストを取得
        Node childNode = node.getFirstChild();

        while ( childNode != null ) {
            String nodeName = childNode.getNodeName();

            // System.out.println( nodeName );
            if ( childNode.hasChildNodes() ) {
                if ( "title".equals( nodeName )
                        || "link".equals( nodeName )
                        || "description".equals( nodeName )
                        || "dc:language".equals( nodeName )
                        || "dc:creator".equals( nodeName )
                        || "dc:date".equals( nodeName )
                        || "sy:updatePeriod".equals( nodeName )
                   ) {
                    channel.put( nodeName, childNode.getFirstChild().getNodeValue() );
                }
            }

            if ( "image".equals( nodeName ) ) {
                channel.put( "image", ( ( Element ) childNode ).getAttribute( "rdf:resource" ) );
            }
            if ( "admin:generatorAgent".equals( nodeName ) ) {
                channel.put( nodeName, ( ( Element ) childNode ).getAttribute( "rdf:resource" ) );
            }

            childNode = childNode.getNextSibling();
        }

    }

    private void parseImage( Node node ) {

        image = new RSSEntity();

        image.put( "rdf:about", ( ( Element ) node ).getAttribute( "rdf:about" ) );

        // 子要素のリストを取得
        Node childNode = node.getFirstChild();

        while ( childNode != null ) {
            String nodeName = childNode.getNodeName();

            // System.out.println( nodeName );
            if ( childNode.hasChildNodes() ) {
                if ( "title".equals( nodeName )
                        || "link".equals( nodeName )
                        || "url".equals( nodeName )
                   ) {
                    image.put( nodeName, childNode.getFirstChild().getNodeValue() );
                }
            }

            childNode = childNode.getNextSibling();
        }

    }

    /**
    * チャネル、イメージ、アイテムなどを格納するクラス
    */
    private class RSSEntity {
        private Map<String, String> map;

        public RSSEntity() {
            map = new LinkedHashMap();
        }

        public void put( String key, String value ) {
            map.put( key, value );
        }

        public String get
            ( String key ) {
            return map.get( key );
        }

        public void iterate() {
            Iterator iterator = map.keySet().iterator();
            while ( iterator.hasNext() ) {
                String key = ( String ) iterator.next();
                String value = map.get( key );
                System.out.println( key + "\t" + value );
            }
        }
    }
}

■実行結果

$ java -cp . RSS1_0  "http://www.doblog.com/weblog/RSSServlet?CMD=LATEST&userid=7160&TYPE=RSS_1_0"
【XMLのバージョン】1.0
【文書のエンコーディング】UTF-8
【ルート要素のタグ名】rdf:RDF
【ルート要素の属性】http://purl.org/rss/1.0/

/** channel */
rdf:about	http://www.doblog.com
title	アラベスク組曲
link	http://www.doblog.com/weblog/myblog/7160
description	All in love is FAIR. /** * 殆どそこはかとない * 絵日記ならぬ * 「写真日記」です。 */

/** item */
rdf:about	http://www.doblog.com/weblog/myblog/7160/2524855#2524855
title	日本−ドイツ戦は31日午前3時半開始 (日刊スポーツ)
link	http://www.doblog.com/weblog/myblog/7160/2524855#2524855
description	&lt;i&gt;日本協会は1日、日本代表のW杯前最後の強化試合となるドイツでの国際親善試合2試合の開始時間を明らかにし、ドイツ戦(レーバークーゼン)は30日午後8時半(日本時間31日午前3時半)、マルタ戦(デュッセルドルフ)は6月4日午後3時(同10時)となった。&lt;/i&gt; だそうです。
dc:date	2006-05-02T16:09:00+09:00
dc:subject	SNAPSHOTS TODAY

/** item */
rdf:about	http://www.doblog.com/weblog/myblog/7160/2524190#2524190
title	マスター・アンド・コマンダー
link	http://www.doblog.com/weblog/myblog/7160/2524190#2524190
description	これもDVD借りてきて観ました。 海原での大嵐の部分が迫力ありました。 内容的には、これもリーダーシップがテーマなんだな、きっと。 「任務優先」を至上のものとしている船長には、親友であり部下である医者との間との葛藤があり、そのあたりがストーリーの展開に深みを与えている。 こういう役をやらせると、ラッセル・クロウはキメてくれます。 #ガラパゴス島、行ってみたいです。
dc:date	2006-05-02T10:26:00+09:00
dc:subject	映画

/** item */
rdf:about	http://www.doblog.com/weblog/myblog/7160/2522708#2522708
title	水辺の風景@立川公園
link	http://www.doblog.com/weblog/myblog/7160/2522708#2522708
dc:date	2006-05-01T23:06:00+09:00
dc:subject	¶公園/立川公園

/** item */
rdf:about	http://www.doblog.com/weblog/myblog/7160/2522674#2522674
title	カルガモ@立川公園
link	http://www.doblog.com/weblog/myblog/7160/2522674#2522674
dc:date	2006-05-01T22:59:00+09:00
dc:subject	√動物たち/鴨

/** item */
rdf:about	http://www.doblog.com/weblog/myblog/7160/2522619#2522619
title	カルガモ@立川公園
link	http://www.doblog.com/weblog/myblog/7160/2522619#2522619
description	ここの鴨は人懐こい。 というか、人からほぼ飼育されているのに等しい。 近所に住む人(犬の散歩をしていたりする)が餌を供給しているようだ。 私にぜんぜん警戒しないで、こんな距離まで例のユーモラスな歩き方でと近づいてきます。
dc:date	2006-05-01T22:49:00+09:00
dc:subject	√動物たち/鴨

/** item */
rdf:about	http://www.doblog.com/weblog/myblog/7160/2522560#2522560
title	花@立川公園
link	http://www.doblog.com/weblog/myblog/7160/2522560#2522560
description	黄色い菖蒲である。 そういえば端午の節句だ。菖蒲湯に浸かろう!
dc:date	2006-05-01T22:36:00+09:00
dc:subject	¶公園/立川公園

/** item */
rdf:about	http://www.doblog.com/weblog/myblog/7160/2522518#2522518
title	鴨の昼寝@立川公園
link	http://www.doblog.com/weblog/myblog/7160/2522518#2522518
description	鴨はこうやって御昼寝するわけです。
dc:date	2006-05-01T22:28:00+09:00
dc:subject	√動物たち/鴨

/** item */
rdf:about	http://www.doblog.com/weblog/myblog/7160/2522488#2522488
title	タンポポ
link	http://www.doblog.com/weblog/myblog/7160/2522488#2522488
description	風に吹かれて、この種子はどこに飛んでいくのか・・・ 想像してみた。
dc:date	2006-05-01T22:23:00+09:00
dc:subject	¶公園/立川公園

/** item */
rdf:about	http://www.doblog.com/weblog/myblog/7160/2522439#2522439
title	貝殻坂@立川公園
link	http://www.doblog.com/weblog/myblog/7160/2522439#2522439
description	暑かった。なんと関東以西では真夏日のところが多かったらしい。 ということで、今日は再び立川公園まで遠征。 今回は珍しく立川公園までの多摩川サイクリングロードではわき目もふらず、一心にひたすら走り抜けた。日差しが強かったんで、かなり日焼けしたかも・・・ 立川公園内に入りようやく一息。 今日はかなり体力を消耗している。このぐらいがいいかもしれない。 #おかげでだいぶ腹もへこんできた(笑)
dc:date	2006-05-01T22:08:00+09:00
dc:subject	¶公園/立川公園

/** item */
rdf:about	http://www.doblog.com/weblog/myblog/7160/2521775#2521775
title	コエンザイム
link	http://www.doblog.com/weblog/myblog/7160/2521775#2521775
description	たまにはこんなものも摂取しています。
dc:date	2006-05-01T18:50:00+09:00
dc:subject	健康

/** item */
rdf:about	http://www.doblog.com/weblog/myblog/7160/2521090#2521090
title	STATISTICS
link	http://www.doblog.com/weblog/myblog/7160/2521090#2521090
description	ポイント: 0.0 総ブログ数: 0 総アクセス数: 0 タイトル: Doblog - メッセージ URL: http://www.doblog.com/weblog/myblog/7000 ポイント: 314.2 総ブログ数: 20 総アクセス数: 6283 タイトル: Doblog - 国際化時代のキャリア戦略 - URL: http://www.doblog.com/weblog/myblog/7001 ポイント: 0.0 総ブログ数: 0 総アクセス数: 24 タイトル: Doblog - デジカメ写真集 - URL: http://www.doblog.com/weblog/myblog/7002 ポイント: 0.0 総ブログ数: 0 総アクセス数: 85 タイトル: Doblog - デジカメ写真集(石田) - URL: http://www.doblog.com/weblog/myblog/7003 ポイント: 6.6 総ブログ数: 66 総アクセス数: 434 タイトル: Doblog - Light Metals Smoothie - URL: http://w...
dc:date	2006-05-01T12:13:00+09:00
dc:subject	おもしろいもの・興味深いもの

/** item */
rdf:about	http://www.doblog.com/weblog/myblog/7160/2520356#2520356
title	ベニスの商人
link	http://www.doblog.com/weblog/myblog/7160/2520356#2520356
description	DVD借りて、観ました。いつも「時間差レンタル」ですが・・・でも新作なので2泊3日。 急いで見ることに。 なんだかんだいって、正直、一番の感想は、ユダヤ商人シャイロックが非常に可哀想で同情したくなったこと。 勿論アル・パチーノの演技が素晴らしかった。 このストーリー(勿論シェークスピア原本)は普遍的な人間の葛藤が描かれている。だから時代を超えて問題提起を今を生きる人にも訴えてくるのでしょう。 結局、この物語は、法とは「詭弁」である、ということがひとつのテーマになっているのかと思う。
dc:date	2006-05-01T01:36:00+09:00
dc:subject	映画

/** item */
rdf:about	http://www.doblog.com/weblog/myblog/7160/2519165#2519165
title	慈恵医大病院の風景
link	http://www.doblog.com/weblog/myblog/7160/2519165#2519165
dc:date	2006-04-30T20:04:00+09:00
dc:subject	REALITIES

/** item */
rdf:about	http://www.doblog.com/weblog/myblog/7160/2519152#2519152
title	stitch
link	http://www.doblog.com/weblog/myblog/7160/2519152#2519152
description	【名-1】 ひと針、縫い目、一針{いっしん}(の縫合{ほうごう})、編目{あみめ}、ステッチ、綴じ、布地{ぬのじ} 【名-2】 さしこみ、脇腹{わきばら}の痛み 【名-3】 〈話〉わずか、ほんの少し 【自動】 縫う 【他動】 〜を縫う、縫い合わせる、とじる ・ He stitched the torn part of the skirt. 彼はスカートの破れた部分を縫い合わせた。 【レベル】5、【発音】sti't∫、【@】スティッチ、ステッチ、【変化】《動》stitches | stitching | stitched stitch a button onto a shirt シャツにボタンを付ける stitch a piece of brightly-coloured embroidery 明るい色の刺しゅうをする stitch a rip ほころびを縫う stitch a wound 傷口{きずぐち}を縫う stitch abscess 縫合部膿瘍{ほうごうぶ のうよう}
dc:date	2006-04-30T20:00:00+09:00
dc:subject	役に立つ英単語・フレーズ

/** item */
rdf:about	http://www.doblog.com/weblog/myblog/7160/2519116#2519116
title	慈恵医大病院
link	http://www.doblog.com/weblog/myblog/7160/2519116#2519116
description	カミサンが昨日夜からひどい腰痛で、今朝朝一で急患センターに向かう。 内臓疾患なのだろうかと、あせったが、血液検査、CTスキャン等の集中検査をして、結局整形外科のスコープにはいる、つまりギックリ腰だったよう。当座は痛み止めでしのげばいいとの処方箋をもらった。 暫く安静にしていれば直るとのことで、正直ほっとした。 結果として、集中検査の結果自体は良好のようで、考えようによっては人間ドックをしたようなものだ。(当然かなりの出費でしたが・・・) とにかく自戒の意味も含め、健康には気をつけなければ。 で、このG/Wはカミサンが当面数日安静(自宅療養)が必要となり、明日からの小旅行(沖縄)はドタキャンということに相成りました。 家族あっての私だし、止むを得ませんが・・・ さあ、これからちょっとの間家事は私と娘で切り回すことに決定です。
dc:date	2006-04-30T19:35:00+09:00
dc:subject	REALITIES

    
戻る

inserted by FC2 system