特集

サイトの更新情報を提供する標準言語RSS

株式会社ピーデー
川俣 晶
2003/08/30

Page1 Page2 Page3

■RSS開発編

MSが提供するサンプル・アプリケーション

 RSSが一部のマニア向けの技術ではない証拠に、マイクロソフト自身が簡単なアグリゲーターのサンプル・アプリケーションを公開している。C#で記述され、.NET Framework上で動作するものである。

 機能は限られており、誤った使い方をすると正常に扱えない設定情報ファイルを保存してしまうなどの問題があるものの、開発の参考にするには十分な内容があるだろう。もし、アグリゲーターを作ってみようと思うなら、これを参考にするとよいだろう。

RSS情報提供機能をASP.NETサイトに付加する

 RSS情報を提供する側のプログラミングはどうなるだろうか。これはそれほど難しい話ではない。定められた定型のXML文書を送信する機能を持たせるだけでよい。これを実現するにあたって、ポイントが3つある。

 1つ目は、どうやってXML文書を送信するかである。これはASP.NETを使えば簡単に実現できる。通常のフォーム上にコントロールを並べる方法と違うので、多少はやり方に関する知識を必要とするが、分かってしまえば難しくない。

 2つ目は、具体的にどうやってXML文書を出力するかだが、.NET Frameworkのクラス・ライブラリにあるXmlTextWriterクラスが使いこなせれば、それで実現できる。汎用のRSS出力用クラス・ライブラリのようなものを作る必要もそれほど感じられないぐらい、簡単なものである。

 3つ目は、多数あるRSSのうち、どのバージョンを使うかである。技術的な必然性がないので、これが最も難しい決断といえるかもしれない。ここでは、神崎正英さんに敬意を表し、RSS 1.0を使って解説を続ける(神崎正英さんは、「RSS -- サイト情報の要約と公開」において、RSS 1.0をこれから注目すべき規格と位置づけている)

 ではさっそく、サンプル・コードを見ていただこう。このサンプル・コードは筆者のサイトで使用しているRSS出力機能のソース・コードを、単独で実行できるように修正したものである。RSS 1.0で記述可能なすべての要素を含んでいるわけではない(筆者のサイトで利用していない情報を出力する機能は含んでいない)が、RSSプログラミングの手始めとしては十分だろう。

 このサンプル・コードを理解するには、RSS 1.0の個々の要素や属性についての知識が必要となる。しかし、それについてここで詳しく説明することは字数の関係上無理なので、詳細については神崎正英さんのRSS -- サイト情報の要約と公開などを参照していただきたい。ここでは概要のみを説明する。

 このサンプル・コードは、Visual Studio .NET 2003でASP.NETのプロジェクトを作成し、そのコード部に入力して動作することを前提としている。

using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Xml;

namespace RSSSample001 {
  public class RSSSample001 : System.Web.UI.Page {
    class Item {
      public readonly string Url;
      public readonly string Title;
      public readonly DateTime UpdatedDateTime;
      public readonly string Digest;

      public Item( string url, string title, DateTime updatedDateTime, string digest ) {
        Url = url;
        Title = title;
        UpdatedDateTime = updatedDateTime;
        Digest = digest;
      }
    }

    private const string rss10ns = "http://purl.org/rss/1.0/";
    private const string rdfns = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
    private const string dcns = "http://purl.org/dc/elements/1.1/";

    private string pageTitle = "サンプル マガジン";
    private string adminstratorName = "サンプル太郎";
    private string uri = "http://mag.autumn.org/";

    private Item [] items = {
      new Item( "http://mag.autumn.org/Content.aspx?id=20030808114723",
        "【小説の洞】 辺境国の「こんぴうた」",
        new DateTime(2003,8,8,11,47,23),
        "世界の中央に大きな国があった。そして、世界の果てには小さな国があった。" ),
      new Item( "http://mag.autumn.org/Content.aspx?id=20030808142640",
        "【技術雑記】 C#で改行を含む長い文字列定数を書く方法",
        new DateTime(2003,8,8,14,26,40),
        "ソース・コードに、改行を含む長い文字列を直接書き込んでしまいたい事例はいろいろあります。"),
      new Item( "http://mag.autumn.org/Content.aspx?id=20030808155512",
        "【MagSite1開発日誌】 0.11にバージョンアップ、RSS出力の名前空間指定を改善",
        new DateTime(2003,8,8,15,55,12),
        "MagSite1を0.11にバージョンアップしました。"),
    };

    private string getRSSDate(DateTime datetime) {
      DateTime utcTime = datetime.ToUniversalTime();
      return utcTime.ToString("yyyy-MM-dd'T'HH:mm:ss'Z'");
    }

    private void Page_Load(object sender, System.EventArgs e) {
      // 出力する項目数は互換のために15個以内の方がよいらしい
      System.Diagnostics.Trace.Assert( items.Length <= 15 );

      Response.ContentType = "application/xml";
      Response.ContentEncoding = System.Text.Encoding.UTF8;

      XmlTextWriter writer = new XmlTextWriter(Response.OutputStream, System.Text.Encoding.UTF8);
      try {
        writer.WriteStartDocument();
        writer.Formatting = Formatting.Indented;

        writer.WriteStartElement("rdf", "RDF", rdfns);
        writer.WriteAttributeString("xmlns", null, rss10ns);
        writer.WriteAttributeString("xmlns", "dc", null, dcns);
        writer.WriteAttributeString("xml", "lang", null, "ja");

        writer.WriteStartElement("channel", rss10ns);
        writer.WriteAttributeString("about", rdfns, Request.Url.AbsoluteUri);
        writer.WriteElementString("title", rss10ns, pageTitle + " Update Information");

        writer.WriteElementString("link", rss10ns, uri);

        writer.WriteElementString("title", dcns, pageTitle);
        writer.WriteElementString("creator", dcns, adminstratorName);

        if( items.Length > 0 ) {
          writer.WriteElementString("date", dcns, getRSSDate(items[items.Length-1].UpdatedDateTime));
        }

        writer.WriteElementString("language", dcns, "ja");
        writer.WriteElementString("description", rss10ns, "このRSSデータは、最近の更新コンテンツです。");

        writer.WriteStartElement("items", rss10ns);
        writer.WriteStartElement("Seq", rdfns);

        foreach( Item item in items ) {
          writer.WriteStartElement("li", rdfns);
          writer.WriteAttributeString("rdf", "resource", item.Url);
          writer.WriteEndElement();
        }

        writer.WriteEndElement();
        writer.WriteEndElement();
        writer.WriteEndElement();

        foreach( Item item in items ) {
          writer.WriteStartElement("item", rss10ns);
          writer.WriteAttributeString("rdf", "about", rdfns, item.Url);

          writer.WriteElementString("title", rss10ns, item.Title);
          writer.WriteElementString("link", rss10ns, item.Url);
          writer.WriteElementString("description", rss10ns, item.Digest);
          writer.WriteElementString("date", dcns, getRSSDate(item.UpdatedDateTime));

          writer.WriteEndElement();
        }
        writer.WriteEndElement();
        writer.WriteEndDocument();
      }
      finally {
        writer.Flush();
      }
    }
    …… Web フォーム デザイナーで生成されたコード ……
  }
}
RSS情報を出力するサンプル・コード

 このサンプル・コードを実行する際には、ASP.NETのHTMLコードを含むファイル(拡張子「.aspx」のファイル)から、HTMLコードを削除しておく必要がある。そこに残すのは、@Pageディレクティブのある最初の1行だけとする。つまり、“<%@ Page 〜”で始まる行だけを残す。

 この手順と、Response.OutputStreamに対して任意の出力を行うコードを組み合わせると、ASP.NETでHTML以外の情報を出力することが可能となる。ここではXML文書を出力しているが、ダイナミックに作成した画像などもこの方法で出力することができる。ASP.NETプログラマーなら知っておくといろいろ役に立つテクニックだろう。

サンプル・コードの実行結果
XMLで記述されたRSS情報が出力される。このページのURLは、SharpReaderなどのアグリゲーターに入力することができる。

 次に、「Response.ContentType = "application/xml";」という行に注目していただきたい。これにより、出力されるコンテンツ・タイプがHTMLではなく、XMLであることが示される。続く

Response.ContentEncoding = System.Text.Encoding.UTF8;

は、出力する文字列がUTF-8でエンコードされることを指定している。この値は、XmlTextWriterクラスのコンストラクタの第2引数と一致している必要がある。

 これで出力の準備はできたが、ストリームにそのまま出力するのは余計な手間が掛かってうれしくない。そこで、XmlTextWriterクラスの登場である。

new XmlTextWriter(Response.OutputStream,System.Text.Encoding.UTF8);

として、クライアントに返送するストリームに対して出力を行うXmlTextWriterクラスのインスタンスを作成する。これに対して、すべての情報を書き出せば、それがクライアントに届くことになる。try……finallyを使って、最後に確実に「writer.Flush();」を実行するように配慮することも忘れないようにしよう。ちなみに、ここはCloseメソッドを呼んで閉じるべきタイミングではないことに注意が必要である。

 次に注意が必要なのが、

writer.WriteAttributeString("xmlns",null,rss10ns);

と、

writer.WriteAttributeString("xmlns", "dc", null, dcns);

という2つの属性の出力である。この2つは、XMLの名前空間を宣言する属性を出力するために使われている。単なる属性の出力とは違うものである。名前空間を示す引数にnullを渡しながら、“xmlns”という接頭辞の属性を出力すると、それは名前空間の宣言であると見なされる。1番目の例は、デフォルト名前空間の指定となっている。2番目の例は、接頭辞付きの指定であり、その後の名前空間付きの出力で、その接頭辞が使われるようになる。

 さて、ここでいくつかの接頭辞について触れておこう。接頭辞なしは、RSS 1.0の名前空間に指定されているが、ほかにいくつかの名前空間が宣言されている。

writer.WriteStartElement("rdf","RDF",rdfns);

として接頭辞rdfに関連付けられている“http://www.w3.org/1999/02/22-rdf-syntax-ns#”は、RDFのResource Description Framework (RDF) Model and Syntax Specificationに対応する名前空間URIである。RSS 1.0はRDFの枠組みの中で使われるものなので、これを参照する必要がある。もう1つ、接頭辞dcに関連付けられている“http://purl.org/dc/elements/1.1/”は、Dublin Core(ダブリン・コア)と呼ばれるメタデータの語彙定義である。Dublin Coreの中核となるのは、基本となる15の要素タイプを定義したDublin Core Metadata Element Setである。RSS 1.0は、このような共通に使用できる既存の語彙を取り込んでいて、「車輪の再発明(同じことを繰り返す無駄なことの例え)」を回避している。

 さて、ここで出力されるXML文書は大きく分けて3つの部分に分けられる。まず、サイトのタイトル(dc:title)や、作成者(dc:creator)を出力する部分。これは、固定的に同じ内容を出力すればよいところである。次に、どんなアイテムがあるか、一覧を示す部分。rdf:li要素を出力している部分がこれに当たる。この要素に付加されたrdf.resource属性が、アイテムを識別する名前を指定している。

 そして、最後に、個々のアイテムの具体的な内容を記述した部分である。item要素を出力している部分がこれに当たる。ここに出力されるrdf.resource属性が、アイテムを識別する名前になり、rdf:li要素のrdf.resource属性と整合している必要がある。ここでは、4つの情報が出力されている。titleはアイテムのタイトル。linkは対象となるデータを示すURI。繰り返すが、RSSはメタデータを扱うもので、メタデータとはデータについてのデータであって、必ずRSSデータの外に、そのRSSデータが言及しているデータが存在するのである。それがこのlink要素で示される。descriptionは概要を示す文字列。dateは日付時刻である。日付時刻のフォーマットは、Dublin Coreで定義されており、それに沿った書式の日付時刻を出力するために、getRSSDateというメソッドを作成してある。

 さて、Resource Description Framework (RDF) Model and Syntax Specificationを丁寧に読んだ方は、「おや?」と首をかしげるかもしれない。というのは、この仕様書を見ると、resource属性に接頭辞は付かないことになっているためだ。しかし、このサンプル・コードには接頭辞が付いている。その理由は、RDFの属性はすべて名前空間修飾するように改められているためだ、という神崎正英さんの指摘による。神崎正英さんの指摘はXMLユーザー・メーリング・リストのアーカイブで参照することができる。このような記述方法の変更を行って既存のソフトでちゃんと使えるのか、ということも気になるが、いまのところ問題なく使えているようである。

おわりに

 筆者は最初に、RSSがいったい何の役に立つのか分からなかった。分からないが、自分のプログラムにRSS対応機能を組み込んでみた。それを行ったのは、単なる新しいもの好き、という動機でしかない。だが、実際に使ってみると、非常に有意義であることが分かった。それ以来、SharpReaderは手放せないソフトとなった。使う前は分かりにくかったが、使ってみるとすぐに有り難みが分かった。

 恐らく、RSSのようなメタデータを扱う技術は、具体的な恩恵が分かりにくい面があると思う。これまで、メタデータの便利さを体験する機会が多くないためである。しかし、これは使えば便利なものである。頭で理解するよりも、身体で理解する方が手っ取り早いかもしれない。まずは、ぜひとも使ってみていただきたい。

 それと同時に、ニュース・サイトなど、更新の多いサイトは、ぜひともRSS情報の提供を行っていただきたい。もし、RSS情報の提供が行われれば、そのサイトがタイムリーに読まれる機会が増えるのではないだろうか?End of Article

 

 INDEX
  [特集]サイトの更新情報を提供する標準言語RSS
     1.RSS入門編:アメリカではやるウェブログとRSSとは?
     2.RSS活用編:SharpReaderでRSSを体験する
   3.RSS開発編:RSS情報提供機能をASP.NETサイトに付加する
 


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間