メンバページ: tsu

行き当たりばったり指向プログラミング

このページは、行き当たりばったりにテーマを決めて、 マイペースで書いていこうと思っています。
といっても、プログラミング回りの話が中心になると思います。
特に、オブジェクト指向が嫌いな方にはおすすめです(嘘かもしれない)。

今回は、RSS 0.91 を扱うための処理を RSS リーダーに組み込んでみることにします。

一般的に RSS 0.91 の xml ファイルは、以下のような形式をしています (注意: 0.91 は rdf ではありません)。 RSS 1.0 と比べるとシンプルです。
(実際には、もっといろんなバリエーションが可能なのですが、ここでは簡単のために最も一般的な例を示しています。)

<?xml version="1.0" encoding="ISO-8859-1" ?>
<rss version="0.91">
<channel>
  <title>RSS の対象となる Web ページのタイトル</title> 
  <link>RSS の対象となる Web ページの URL</link> 
  <description>RSS の対象となる Web ページの概要</description> 
  <language>言語(日本語の場合は ja)</language> 
  <copyright>RSS の対象となる Web ページに関する著作権に関する情報</copyright> 
  <managingEditor>RSS の対象となる Web ページの編集者のemailアドレス</managingEditor> 
  <webMaster>RSS の対象となる Web ページの管理者のemailアドレス</webMaster> 
  <item>
    <title>RSS 生成対象の 最初 の記事の 題名</title> 
    <link>RSS 生成対象の 最初 の記事の URL</link> 
    <description>RSS 生成対象の 最初 の記事の 概要</description> 
  </item>
  <item>
    <title>RSS 生成対象の 2番目 の記事の 題名</title> 
    <link>RSS 生成対象の 2番目 の記事の URL</link> 
    <description>RSS 生成対象の 2番目 の記事の 概要</description> 
  </item>
  ・・・・・・・・・・・・(略)・・・・・・・・・・・・
  <item>
    <title>RSS 生成対象の n番目 の記事の 題名</title> 
    <link>RSS 生成対象の n番目 の記事の URL</link> 
    <description>RSS 生成対象の n番目 の記事の 概要</description> 
  </item>
</channel>
</rss>

入力ファイルに

<rss version="0.91">

という文字列が含まれていたら、RSS 0.91 と見なすことにします。
RSS 0.91 のリーダー readRSS_0_91() を やっつけ (^^; で作ると、 以下のようになります(しつこいようですが、念のために書いておきます。以下のコードは、後日、リファクタリングを堪能するため、わざと突っ込みどころのあるコードを書いています。そうは言っても、一応、ちゃんと動かないと話にならないので、動作確認はしてあります)。

int readRSS_0_91( FILE *input, FILE *output, int mode, const char *encoding )
{
    char    buf[BUFSIZ], *p, *q, *r;
    int     ret = 0;
    char    title[BUFSIZ];
    char    link[BUFSIZ];
    char    description[BUFSIZ];
    char    language[BUFSIZ];
    int     cnt = 0;

    language[0] = '\0';

    while ( ( p = fgets( buf, BUFSIZ - 1, input ) ) != NULL ) {
        while ( (*p == ' ') || (*p == '\t') )
            p++;

        if ( !strncmp( p, "<title>", 7 ) ) {
            q = strchr( p + 7, '<' );
            if ( q ) {
                strncpy( title, p + 7, q - (p + 7) );
                title[q - (p + 7)] = '\0';
            }
            else {
                strcpy( title, p + 13 );
                while ( ( p = fgets( buf, BUFSIZ - 1, input ) ) != NULL ) {
                    while ( (*p == ' ') || (*p == '\t') )
                        p++;

                    strcat( title, " " );
                    strcat( title, p );
                    if ( ( q = strchr( title, '<' ) ) != NULL ) {
                        *q = '\0';
                        break;
                    }
                }
            }
        }
        else
        if ( !strncmp( p, "<link>", 6 ) ) {
            q = strchr( p + 6, '<' );
            if ( q ) {
                strncpy( link, p + 6, q - (p + 6) );
                link[q - (p + 6)] = '\0';
            }
        }
        else
        if ( !strncmp( p, "<description>", 13 ) ) {
            q = strchr( p + 13, '<' );
            if ( q ) {
                strncpy( description, p + 13, q - (p + 13) );
                description[q - (p + 13)] = '\0';
            }
            else {
                strcpy( description, p + 13 );
                while ( ( p = fgets( buf, BUFSIZ - 1, input ) ) != NULL ) {
                    while ( (*p == ' ') || (*p == '\t') )
                        p++;

                    strcat( description, " " );
                    strcat( description, p );
                    if ( ( q = strchr( description, '<' ) ) != NULL ) {
                        *q = '\0';
                        break;
                    }
                }
            }
        }
        else
        if ( !strncmp( p, "<language>", 10 ) ) {
            q = strchr( p + 10, '<' );
            if ( q ) {
                strncpy( language, p + 10, q - (p + 10) );
                language[q - (p + 10)] = '\0';
            }
        }
        else if ( !strncmp( p, "<item>", 6 ) )
            break;
    }

    fprintf( output,
             "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD "
             "HTML 4.01 Transitional//EN\">\n" );

    if ( language[0] )
        fprintf( output, "<html lang=\"%s\">\n<head>\n", language );
    else
        fprintf( output, "<html>\n<head>\n" );

    fprintf( output,
             "<meta http-equiv=\"Content-Type\" content=\"text/html; "
             "charset=%s\">\n", encoding );
    fprintf( output, "<title>%s</title>\n", title );
    fprintf( output, "</head>\n\n<body>\n" );

    fprintf( output, "<h1><a href=\"%s\">%s</a></h1>\n", link, title );
    fprintf( output, "<h2>%s</h2>\n", description );

    while ( ( p = fgets( buf, BUFSIZ - 1, input ) ) != NULL ) {
        while ( (*p == ' ') || (*p == '\t') )
            p++;
        if ( !strncmp( p, "<item>", 6 ) || (cnt == 0) ) {
            cnt++;

            if ( cnt == 1 )
                fputs( "<ul>\n", output );
            title[0]       = '\0';
            link[0]        = '\0';
            description[0] = '\0';

            if ( cnt > 1 )
                continue;
        }

        if ( cnt >= 1 ) {
            if ( !strncmp( p, "<title>", 7 ) ) {
                q = strchr( p + 7, '<' );
                strncpy( title, p + 7, q - (p + 7) );
                title[q - (p + 7)] = '\0';
            }
            else
            if ( !strncmp( p, "<link>", 6 ) ) {
                q = strchr( p + 6, '<' );
                strncpy( link, p + 6, q - (p + 6) );
                link[q - (p + 6)] = '\0';
            }
            else
            if ( !strncmp( p, "<description>", 13 ) ) {
                q = strchr( p + 13, '<' );
                if ( q && !strncmpi( q, "<![CDATA[", 9 ) ) {
                    p += 9;
                    r = strchr( q, '>' );
                    if ( r ) {
                        *r = '\0';
                        while ( *--r == ']' )
                            *r = '\0';
                    }
                    q += 9;
                    strcpy( description, q );
                }
                else if ( q ) {
                    strncpy( description, p + 13, q - (p + 13) );
                    description[q - (p + 13)] = '\0';
                }
            }
            else
            if ( !strncmp( p, "</item>", 7 ) ) {
                if ( title[0] && link[0] && description[0] ) {
                    fprintf( output,
                             "<li><a href=\"%s\">%s</a><br>",
                             link, title, description );

                    fputs( "</li>\n", output );

                    title[0]       = '\0';
                    link[0]        = '\0';
                    description[0] = '\0';
                }
            }
        }
    }

    if ( cnt >= 1 )
        fputs( "</ul>\n", output );

    fprintf( output, "</body>\n</html>\n" );

    return ( ret );
}

今回、作成した関数のプロトタイプ宣言をヘッダファイルに追加しておきます。

/*
 *  readRSS
 *      RSS ファイルを元に html ファイルを生成する
 *      written by H.Tsujimura   15 Dec 2003
 *
 * History:
 * $Log: readRSS.h $
 * Revision 1.2  2004/03/17  00:33:35  tsujimura543
 * RSS 0.91 対応
 *
 * Revision 1.1  2003/12/15  10:50:51  tsujimura543
 * Initial revision
 *
 */

#ifndef __READRSS_H__
#define __READRSS_H__

#ifdef   __READRSS_C__
#ifndef	lint
static char	*rcs_id_header =
"$Header: C:/user/local/src/makeRSS/src/readRSS/RCS/readRSS.h 1.2 2004/03/17 00:33:35 tsujimura543 Exp tsujimura543 $";
#endif
#endif

/* mode */
#define MODE_NORMAL     0       /* normal html */
#define MODE_I_MODE     1       /* for i-mode  */
#define MODE_J_SKY      2       /* for J-SKY   */
#define MODE_EZWEB      3       /* for EZweb   */
#define MODE_OTHER      0x7F    /* for others (L-mode, H", astel) */

/* RSS version */
/*
 *   RSS 0.91 -+------------------------------------------------------------
 *             +- RSS 1.0 --------------------------------------------------
 *             +- RSS 0.92 -- RSS 0.93 -+-----------------------------------
 *                                      +- RSS 2.0  ------------------------
 *                                      +- ATOM 0.1 -- ATOM 0.2 -+----------
 *                                                               +- ATOM 0.3
 */
#define VER_UNDEFINED   0
#define VER_RSS_0_91    0x01
#define VER_RSS_0_92    0x12
#define VER_RSS_0_93    0x13
#define VER_RSS_1_00    0x02
#define VER_RSS_2_00    0x14
#define VER_RSS_3_00    0x25    /* 対応しない */

/* ATOM は将来対応(しないかも?) */
#define VER_ATOM_0_1    0x34
#define VER_ATOM_0_2    0x35
#define VER_ATOM_0_3    0x36

int readRSS( FILE *input, FILE *output, int mode );

int readRSS_0_91( FILE *input, FILE *output, int mode, const char *encoding );
int readRSS_1_00( FILE *input, FILE *output, int mode, const char *encoding );
int readRSS_2_00( FILE *input, FILE *output, int mode, const char *encoding );

char    *dateString( const char *date, const char *encoding );
char    *categoryString( const char *encoding );

#endif  /* __READRSS_H__ */

readRSS() の RSS 版数判定部分を以下のように書き換えて、 今回作った readRSS_0_91() を組み込めば OK。

        /* RSS の版数を判定し、対応する RSS リーダーを呼び出す */
        if ( !strncmp( p, "xmlns=\"http://purl.org/rss/1.0/\"", 32 ) ) {
            version = VER_RSS_1_00;
            ret = readRSS_1_00( input, output, mode, encoding );
            break;
        }

        if ( !strncmp( p, "<rss version=\"0.91\">", 20 ) ) {
            version = VER_RSS_0_91;
            ret = readRSS_0_91( input, output, mode, encoding );
            break;
        }

次回は RSS 2.0 のリーダーを作ってみることにします。

(つづく)

目次

第1回 RSSリーダを作ってみる 巻の1
まずは所信表明。
第2回 RSSリーダを作ってみる 巻の2
RSS 1.0 のリーダーを作成します
第3回 RSSリーダを作ってみる 巻の3
RSS 0.91 のリーダーを作成します
第4回 RSSリーダを作ってみる 巻の4
RSS 2.0 のリーダーを作成します
第5回 RSSリーダを作ってみる 巻の5
Atom 0.3 のリーダーを作成します
第6回 RSSリーダを作ってみる 巻の6
ユーティリティ関数を用意します
第7回 RSSリーダを作ってみる 巻の7
リファクタリングを開始します

RSS とは?

今後の予定

第8回 RSSリーダを作ってみる 巻の8
さらにリファクタリングしてみます
第9回 RSSリーダを作ってみる 巻の9
どんどんリファクタリングします


Copyright (c) 2004, 2010 Oki Software Co., Ltd.