XSLT を使用して Atom 1.0 を処理する

XPath 式を使って Atom 文書をナビゲートし、XSLT を適用して Atom ソース・ファイルを作成、変換する

Atom 1.0 は、Web サイトのコンテンツに関する情報の更新である Web フィードのための新しい IETF (Internet Engineering Task Force) 標準です。Atom は XML フォーマットであることから、Atom を処理するには XSLT が強力なツールになります。このチュートリアルでは、著者である Uche Ogbuji が、XSLT を使用して Atom 文書を処理する手法を実際の事例への対処方法と併せて説明します (訳注: この記事は、原文が最初に公開された 2005年現在の状況に基づいて書かれたものです)。

2012年 5月 29日 ― 「参考文献」の 3 つのリンク切れを修正しました。

2012年 5月 31日 ― 著者からの要望により、「参考文献」に記載されている「RELAX NG for Atom 1.0」のリンクを更新しました。

Uche Ogbuji, Principal Consultant, Fourthought, Inc.

Photo of Uche OgbujiUche Ogbuji は、XML によるエンタープライズ・ナレッジ・マネジメントのソリューションを専門とするソフトウェア・ベンダーおよびコンサルタント会社である Fourthought Inc. の共同設立者です。Fourthought では、XML、RDF、およびナレッジ・マネジメント・アプリケーションを対象としたオープンソースのプラットフォーム、4Suite を開発しています。彼は Versa RDF 照会言語の主任開発者でもあります。コンピューター・エンジニア、ライターとしても活躍する彼は、ナイジェリア出身で、現在はアメリカ・コロラド州ボールダー在住です。Ogbuji についての詳細は、彼のウェブログ「Copia」に記載されています。



2012年 9月 27日

始める前に

はじめに、このチュートリアルから学べる内容、そしてチュートリアルを最大限に活用する方法を紹介します。

このチュートリアルについて

このチュートリアルでは、XSLT で Atom 1.0 を処理する方法について段階を追って説明します。Atom は、時間の経過とともにコンテンツが何らかの方法で変更される Web サイトについての情報を伝達するための、重要なフォーマットです。こうしたコンテンツの例としては、ときどき新しいエントリーが公開されるウェブログや、イベント・リスト、マルチメディア・プログラム、スケジュールなど、さまざまなものがあります。Atom がカバーする範囲の広さは、そのホーム・ページで以下のように説明されています。

Atom とは、XML ベースの Web コンテンツおよびメタデータの配信フォーマットの名前であり、定期的に更新される Web サイトに属する Web リソースを公開および編集するためのアプリケーション・レベルのプロトコルです。

すべての Atom フィードは、整形式 XML 文書であることが要件となります。Atom フィードは、メディア・タイプ application/atom+xml によって識別されます。

Atom では整形式であることが極めて重要であることから、Atom を処理する技術として真っ先に頭に浮かぶのは、XSLT です。XSLT は、XML 間でフォーマットを変換したり、XML をテキストや表示用の HTML に変換したりするためのドメイン特化言語です。XSLT 変換は、事実上プラットフォームにも言語にも依存しない Atom の処理手段となります。このチュートリアルでは、XSLT で Atom を処理する上で欠かせない要素について説明します。

目標

このチュートリアルでは、XPath 式を使用して Atom 1.0 文書の基本構造をナビゲートする方法、XPath 式を使用して Atom ソース・ファイルの XSLT 変換を行う方法、そして Atom ファイルに埋め込まれたテキストとマークアップの複雑な関係に対処する方法を説明します。さらに、XSLT テンプレートを使用して妥当な Atom ファイルを生成する方法と、生成されたファイルの妥当性を検証する方法についても説明します。

前提条件

このチュートリアルで対象としている読者は、XML、XPath、および XSLT を熟知している開発者です。XHTML と Atom についてもある程度の知識が必要ですが、Atom は単純なフォーマットなので、このチュートリアルの最初の方にあるサンプル・コードを見れば、十分理解できるはずです。これらのトピックに関する記事およびチュートリアルについては、「参考文献」を参照してください。チュートリアルに記載されているサンプルのいくつかは、「参考文献」に記載されている Atom 1.0 に関する基礎知識を紹介する記事から引用しています。

システム要件

このチュートリアルのサンプルを実行するには、XSLT プロセッサーが必要です。できれば、EXSLT をサポートしている XSLT プロセッサーを使用してください (「参考文献」を参照)。チュートリアルで使用するのは、4Suite XML 1.0b2 です。また、Web ブラウザーも必要です。ブラウザーの出力例を示すときには、Fedora Core 4 Linux で動作する Firefox 1.0.7 のスクリーン・ショットを使用します。Firefox は、Windows、Mac OS X、Linux、その他のプラットフォームで使用できる人気の Web ブラウザーです。


Atom からフィールドを読み取る

Atom 1.0 は、IETF (Internet Engineering Task Force) RFC 4287 となっています。Atom 1.0 は非常に明確に定義されているので、Atom 文書の構造にも、Atom 文書から情報を抽出するにも確信を持って対処できるはずです。

最上位レベルの構造と名前空間

あらゆる Atom 文書に言えることですが、XML 宣言を組み込み、エンコーディングを指定しておくのが賢明です。XML 宣言は XSLT には透過的であるため、XSLT では Unicode と XPath のデータ・モデルに基づく構成体を処理することになります。すべての Atom 1.0 要素は名前空間 http://www.w3.org/2005/Atom にあります。この名前空間に接頭辞が必要な場合 (例えば、XPath 式)、このチュートリアルでは一貫して接頭辞として a を使用します。実際、サンプル・コードの多くでは、Atom 1.0 名前空間がデフォルトとして設定されます。

リスト 1 (atom-basic.xml) は、完全な Atom 1.0 文書の例です。

リスト 1. 完全な Atom 1.0 の例 (atom-basic.xml)
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"
      xml:lang="en"
      xml:base="http://www.example.org">
  <id>http://www.example.org/myfeed</id>
  <title>My Simple Feed</title>
  <updated>2005-07-15T12:00:00Z</updated>
  <link href="/blog" />
  <link rel="self" href="/myfeed" />
  <author><name>Uche Ogbuji</name></author>
  <entry>
    <id>http://www.example.org/entries/1</id>
    <title>A simple blog entry</title>
    <link href="/blog/2005/07/1" />
    <updated>2005-07-14T12:00:00Z</updated>
    <summary>This is a simple blog entry</summary>
  </entry>
  <entry>
    <id>http://www.example.org/entries/2</id>
    <title />
    <link href="/blog/2005/07/2" />
    <updated>2005-07-15T12:00:00Z</updated>
    <summary>This is simple blog entry without a title</summary>
  </entry>
</feed>

すべての Atom 文書には、最上位レベルに feed 要素があり、その下位レベルに 1 つ以上の entry 要素がある場合と entry 要素がない場合があります。feed 要素と entry 要素には、以下の 3 つの要素を含める必要があります。

  • id ― グローバルで一意に決まる ID
  • title ― 空の要素にすることもできますが、通常はタイトルを含めることを強く推奨します。
  • updated ― エントリーまたはフィードが最後に更新された日時のタイムスタンプ

ID、タイトル、更新日時

id 要素には単純なテキストが入ります。フィード全体の ID には、XPath 式 /a:feed/a:id を使用してアクセスすることがきます。エントリーの ID をすべて取得するには、常に /a:feed/a:entry/a:id を使用します。

title 要素の内容は、簡潔な構造化テキストを目的とした Atom の慎重な規則に従います。この要素のフィールドについては、次のセクションで詳しく説明します。とりあえずは、この要素の値が文字列であることに注意してください。フィード全体のタイトルには、/a:feed/a:title でアクセスすることができます。

updated 要素には、完全な ISO-8601 日時フォーマットでの日時が入ります。目的によっては、この値を単純なテキストとして扱うこともできます。XSLT での高度な日時処理手法について詳しく学ぶには、「参考文献」で紹介している記事を読んでください。フィード全体の更新日時には、/a:feed/a:updated でアクセスすることができます。

リンク

Atom フィードには、ほぼ決まって、rel 属性に値 self を持つ link 要素が 1 つ以上あります。このリンクはフィード自体の正式な URL を指します。フィード自体のリンクにアクセスする場合に使用する XPath 式は、/a:feed/a:link[@rel='self'] です。リスト 1 では、フィード自体のリンクの値が /myfeed となっています。これは相対 URL であるため、正しく処理するには絶対 URL に変換する必要があります。そこで活躍するのが、xml:base 属性です。処理ソフトウェアは xml:base 属性の値を使用することで、ベース URL (http://www.example.org) に対する相対値を解決して、絶対 URL の http://www.example.org/myfeed を取得する必要があります。このような変換を XPath 1.0 を使用して行うことはできませんが (XPath 2.0 には相対 URL を解決するための、resolve-uri 関数が含まれています)、処理した結果の送信先となるシステムで URI ベースの処理を使用できる場合には問題ありません。例えば HTML を生成しているのであれば、相対 URI を使用することができますが、必ず HTML 内にベース URI が示されるようにします。これについては、後のセクションで具体的に説明します。

他のリンクには、関連するリンク属性に基づいてアクセスします。通常、エントリーには (そのエントリーの Web 表現への) メイン・リンクがあります。メイン・リンクには、一般に a:link[not(@rel)] を使用してアクセスすることができます。

注: 実際には、Atom での URI は IRI (Internationalized Resource Identifier) として指定されます。IRI は、RFC 3987 に定義されています (「参考文献」を参照)。ただし、ほとんどの読者にとって親しみがある用語は URI のほうなので、このチュートリアルでは URI で通します。

作成者とコントリビューター

Atom では、帰属を明確にすることが要件となっています。具体的に言うと、すべてのエントリーに少なくとも 1 つ以上の author 要素が指定されていなければ、フィードに対して author 要素が 1 つ以上必要になります。これは厳しい制約のように思えるかもしれませんが、時間の経過とともに変更される Web コンテンツの世界で、情報を一部抜粋して別の目的で使用する場合がいかに多いかを考えると、実は望ましいプラクティスです。Atom では、それぞれの情報の作成者が明確にわかるようにしているというわけです。1 つのフィードまたはエントリーに、1 つ以上の contributor 要素を含めることもできます。Atom では、作成者とコントリビューターは、必須の name 子要素 (プレーン・テキスト) と、オプションの uri 子要素 (URI) および email 子要素 (プレーン・テキストの e-メール・アドレス) からなる構造化要素として表現されます。フィード全体の作成者の情報がある場合、その作成者の名前にアクセスするには、XPath a:feed/a:author/a:name を使用します。

カテゴリー

皆さんもおそらく耳にしたことがあるかと思いますが、(原文の記事が最初に公開された 2005年時点では) タギングがホットなトピックとなっています。タギングとは、時間の経過とともに変更される Web サイトのエントリーに、タグという形でメタデータを関連付けるプラクティスです。タグとは、その項目のカテゴリーまたは関連する主題を表わす単純な言葉であり、人々はこれらのタグを使って、関連する情報を辿ることができます。したがって、タグを使用すれば、例えばウェブログのエントリー、予定されているイベント、写真、オーディオ・クリップをはじめ、さまざまな一般的カテゴリーを組み合わせることができます。Atom では、(ありがたいことに) 表現豊かな形でタグをサポートしています。フィードやエントリーに category 要素を持たせ、この要素に必須の term 要素と、オプションでその他のメタデータを含めることができます。

上記の他の Atom 要素についても、以降のセクションでいくつか取り上げます。一般的に使用されていない要素や、このチュートリアルで紹介する手法を使えば通常処理できる要素については取り上げません。

XSLT で組み立てる

ここまでの説明で、Atom フィードの要素にアクセスする方法について十分理解しているはずなので、初めての XSLT の例も理解できることと思います。リスト 2 に記載する変換 (tickertape.xslt.xml) は、Atom フィードをプレーン・テキストの単純なリストとして要約します。これは、人間が読解可能なティッカー・テープ (訳注: ティッカー・テープとは、昔の株取引で使われていた、株価情報が打ち込まれた紙テープのこと) のフィード版だと思ってください。

リスト 2. Atom フィードの主要なフィールドを要約したティッカー・テープとしての単純な XSLT ファイル (tickertape.xslt.xml)
<?xml version="1.0" encoding="utf-8"?>
<xsl:transform  version="1.0"
  xmlns:a="http://www.w3.org/2005/Atom"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>

  <xsl:strip-space elements="*"/>
  <xsl:output method="text"/>

  <xsl:template match="*"/>

  <xsl:template match="a:feed">
    <xsl:text>Atom Feed: </xsl:text><xsl:value-of select="a:id"/>
    <xsl:text>&#10;</xsl:text>
    <xsl:apply-templates/>
  </xsl:template>

  <xsl:template match="a:entry">
    <xsl:text>  ----------------------------------------&#10;</xsl:text>
    <xsl:text>  Feed entry: </xsl:text><xsl:value-of select="a:id"/>
    <xsl:text>&#10;</xsl:text>
    <xsl:apply-templates/>
  </xsl:template>

  <xsl:template match="a:title|a:updated">
    <xsl:if test="parent::a:entry">
      <xsl:value-of select="'  '"/>
    </xsl:if>
    <xsl:value-of select="local-name()"/>:<xsl:apply-templates/>
    <xsl:text>&#10;</xsl:text>
  </xsl:template>

</xsl:transform>

おそらく最初に気付く点は、このリストは大方のところ、テンプレートを多用したプッシュ・スタイルの XSLT であることです。したがって、これまでに説明した XPath 式の多くは見当たりません。それでもやはり、XSLT で対処するノード構造を理解するには XPath 式が役立ちます。Atom ではフィードとエントリーにメタデータ要素の名前を再使用するので、リストの最後のテンプレートにフィードとエントリーの処理を統合することができます。出力テキストのフォーマット設定を制御するために、xsl:strip-spacexsl:text、および &#10; (改行の数値文字参照) が使用されていることに注意してください。

Web ブラウザーからサンプル XSLT を実行する

変換を適用してその結果をブラウザーに表示するには、XSLT スタイルシートの PI (Processing Instruction: 処理命令) を追加してください。atom-basic-1.xml (「ダウンロード」を参照) は、PI が追加されているという点を除き、リスト 1 (atom-basic.xml) と同じです。以下に、PI を追加したバージョンの最初の 3 行を記載します。

<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xml" href="tickertape.xslt.xml"?>
<feed xmlns="http://www.w3.org/2005/Atom"

リスト 2 では拡張子として xslt.xml を使用しています。これは、Mozilla ベースのブラウザーでは、ローカル・ディスクから取得したファイルに .xsl または .xslt の拡張子が使われていると、ファイルの XML メディア・タイプを推測できないことがあるためです。推測できない場合には、スタイルシートをロードする際にエラーが発生します。このような問題を回避する最も確実な方法として私が至った結論は、XSLT ファイル名の終わりを .xml にすることです。atom-basic-1.xml をブラウザーにロードすると、図 1 のように表示されます。

図 1. リスト 1 にリスト 2 を適用した場合のブラウザー出力
ブラウザーに表示された atom-basic-1.xml

コマンドラインからサンプル XSLT を実行する

上記の変換は、コマンド・ライン・ツールから実行することもできます。例えば 4Suite の 4xslt コマンドライン・ツールでは、プレーン・ソース・ファイル (atom-basic.xml) と XSLT ファイル (tickertape.xslt.xml) を指定する方法、あるいはソース・ファイルだけをスタイルシート PI (atom-basic-1.xml) と併せて使用する方法のいずれかを使用することができます。図 2 に、両方の方法によるコンソール出力を示します。

図 2. リスト 1 にリスト 2 を適用するコマンドライン・セッション
コマンドラインによる Atom 文書でのXSLT 呼び出し

以降の例に従う際には、コマンドライン・プロセッサーと Web ブラウザーのどちらを使用するかを決めてください。あるいは、都合に合わせて XSLT IDE などの他のツールを使用することもできます。


Atom のコンテンツ・フィールドを処理する

Atom の中心となるのは、コンテンツです。これらのコンテンツが、フィードの基になる Web サイトのプレビューを提供します。けれども、HTML の混沌とした凡例が原因で、人々が望むあらゆるコンテンツの表示方法に対処するとなると、かなり厄介なことになります。他の Web フィード・フォーマット (RSS 2.0 など) に比べ、Atom で行われている最も重要な改善内容の 1 つは、コンテンツの表示方法に関する、その非常に明白かつ慎重なルールです。

タイトルの詳細

前のセクションでは、タイトルを単なるプレーン・テキストとして、とりあえず単純化して示しました。これは、リスト 1 に示されているすべてのタイトルに当てはまります。しかし、タイトルでマークアップを使用することもできます。ただしそれには、type 属性 (デフォルトでは textに設定されます) を使用して、リッチな形式のテキストとしてマークアップしなければなりません。例えばリスト 3 に示すように、type="html" を設定してから HTML を使用し、妥当な XML 文字データになるように特殊文字をエスケープします。

リスト 3. HTML を使用したタイトルの例
<title type="html">
   Making an &lt;strong&gt;emphatic&lt;/strong&gt; statement
</title>

このように特殊文字をエスケープすると、要素に含まれるマークアップが二級市民となり、処理が複雑になってしまいます。こうするよりも、埋め込み XHTML を使用したほうが遥かに賢い方法となります。埋め込み XHTML はエスケープせずに Atom に埋め込まれるため、処理が容易になるからです。リスト 4 のコードは、表示される内容はリスト 3 と同じですが、XHTML コンテンツの構成体を使用しています。

リスト 4. タイプとして XHTML を使用したタイトルの例
<title type="xhtml">
  <div xmlns="http://www.w3.org/1999/xhtml">
    Making an <strong>emphatic</strong> statement
  </div>
</title>

埋め込み要素は、XHTML 名前空間の中になければならないため、上記の例ではデフォルト名前空間を再定義しています。また、このようなコンテンツは div 要素にラップしなければなりません。div 要素は表現されるマークアップの 1 つとは見なされず、マーカーと見なされます。

XHTML コンテンツの例

XHTML はその重要性から、Atom で配信するには理想的なコンテンツの構成体となっています。リスト 5 に、XHTML テキストの構成体を使用した、今までよりも複雑な Atom 1.0 の例を記載します。

リスト 5. XHTML の構成体を使用した Atom 1.0 の例 (atom-with-xhtml.xml)
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"
      xml:lang="en"
      xml:base="http://copia.ogbuji.net">
  <id>http://copia.ogbuji.net/atom1.0</id>
  <title>Copia</title>
  <updated>2005-07-15T12:00:00Z</updated>
  <author>
    <name>Uche Ogbuji</name>
    <uri>http://uche.ogbuji.net</uri>
    <email>uche@ogbuji.net</email>
  </author>
  <link href="/blog" />
  <link rel="self" href="/blog/atom1.0" />
  <entry>
    <id>http://copia.ogbuji.net/blog/2005-09-16/xhtml</id>
    <title>XHTML tutorial pubbed</title>
    <link href="http://copia.ogbuji.net/blog/2005-09-16/xhtml"/>
    <category term="xml"/>
    <category term="css"/>
    <category term="xhtml"/>
    <updated>2005-07-15T12:00:00Z</updated>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
	<p>
	  <a href="http://www.ibm.com/developerworks/edu/x-dw-x-xhtml-i.html">
	    "XHTML, step-by-step"
	  </a>
	</p>
	<blockquote>
	  <p>Start working with Extensible Hypertext Markup
	  Language. In this tutorial, author Uche Ogbuji shows you how to use
	  XHTML in practical Web sites.</p>
	</blockquote>
	<p>In this tutorial</p>
	<ul>
	  <li>Tutorial introduction</li>
	  <li>Anatomy of an XHTML Web page</li>
	  
	  <li>Understand the ground rules</li>
	  <li>Replace common HTML idioms</li>
	  <li>Some practical considerations</li>
	  <li>Wrap up</li>
	</ul>
      </div>
    </content>
  </entry>
  <entry>
    <id>http://copia.ogbuji.net/blog/2005-06-21/XSLT___CSS</id>
    <title>XSLT + CSS tutorial pubbed</title>
    <link href="http://copia.ogbuji.net/blog/2005-06-21/XSLT___CSS" />
    <category term="xml"/>
    <category term="css"/>
    <category term="xslt"/>
    <updated>2005-07-14T12:00:00Z</updated>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
	<p>
	  <a href="http://www.ibm.com/developerworks/edu/x-dw-x-xmlcss3-i.html">
	    "Use Cascading Stylesheets to display XML, Part 3"
	  </a>
	</p>
	<blockquote>
	  <p>CSS isn't just for HTML anymore! Learn to combine the strengths
             of CSS with those of XSLT and fine-tune your XML presentation
             in a browser.</p>
	</blockquote>
        <ul>
	  <li>
	  <a href="http://www.ibm.com/developerworks/edu/x-dw-x-xmlcss-i.html">
	  "Use Cascading Stylesheets to display XML, Part 1"</a>
	  which introduces the use of CSS to style XML in browsers
	  (November 2004)</li>
	  <li><a href="http://www.ibm.com/developerworks/edu/x-dw-x-xmlcss2-i.html">
	  "Use Cascading Stylesheets to display XML, Part 2"</a>
	  which covers advanced topics for the use of CSS to style XML
	  in browsers (February 2005)</li>
	</ul>
      </div>
    </content>
  </entry>
</feed>

contentcategory は、この例で初めて登場した新しい要素です。xhtml というタイプが指定されたコンテンツは、基本的に、Atom というフィードの中に異なるフォーマットのアイランドを作成します。このことが XSLT 処理におけるいくつかの難題を生み出すため、モジュール化変換およびプッシュ・スタイルの処理が強力に支持されます。これらのプラクティスについては、このチュートリアル全体を通して説明します。

XHTML への変換

リスト 6 (atom2xhtml.xslt.xml) は、極めてモジュール化が進んだ、Atom から XHTML 1.1への変換です。この変換は、テキスト構造と XHTML コンテンツ構造をサポートします。

リスト 6. Atom フィードの XHTML ビューを提供する XSLT 変換 (atom2xhtml.xslt.xml)
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:a="http://www.w3.org/2005/Atom"
  xmlns:xhtml="http://www.w3.org/1999/xhtml" 
  xmlns="http://www.w3.org/1999/xhtml" 
  exclude-result-prefixes="a xhtml">

  <xsl:output method="xml" encoding="utf-8"
              doctype-public="-//W3C//DTD XHTML 1.1//EN"
              doctype-system="http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"/>

  <xsl:template match="*"/><!-- Ignore unknown elements -->
  <xsl:template match="*" mode="links"/>
  <xsl:template match="*" mode="categories"/>

  <xsl:template match="a:feed">
<html xml:lang="en">
  <head>
    <title><xsl:value-of select="a:title"/></title>
  </head>
  <body>
    <h1><xsl:apply-templates select="a:title" mode="text-construct"/></h1>
    <xsl:apply-templates/>
    <p>Feed ID: <xsl:value-of select="a:id"/></p>
    <p>Feed updated: <xsl:value-of select="a:updated"/></p>
    <xsl:apply-templates/>
  </body>
</html>
  </xsl:template>

  <xsl:template match="a:summary">
    <div class="summary">
      <xsl:apply-templates select="." mode="text-construct"/>
    </div>
  </xsl:template>

  <xsl:template match="a:content">
    <div class="content">
      <xsl:apply-templates select="." mode="text-construct"/>
    </div>
  </xsl:template>

  <xsl:template match="a:entry">
    <div class="entry">
      <h2><xsl:apply-templates select="a:title" mode="text-construct"/></h2>
      <div class="id">Entry ID: <xsl:value-of select="a:id"/></div>
      <div class="updated">Entry updated: <xsl:value-of select="a:updated"/></div>
      <div class="links">
	<xsl:text/>Links: <xsl:apply-templates select="a:link" mode="links"/>
      </div>
      <div class="categories">
	<xsl:text>Categories: </xsl:text>
	<xsl:apply-templates select="a:category" mode="categories"/>
      </div>
      <xsl:apply-templates/>
    </div>
  </xsl:template>

  <xsl:template match="a:link" mode="links">
    <a href="{@href}">
      <xsl:value-of select="@rel"/>
      <xsl:if test="not(@rel)">[generic link]</xsl:if>
      <xsl:if test="@type">
	<xsl:text> (</xsl:text><xsl:value-of select="@type"/><xsl:text>): </xsl:text>
      </xsl:if>
      <xsl:value-of select="@title"/>
    </a>
    <xsl:if test="position() != last()">
      <xsl:text> | </xsl:text>
    </xsl:if>
  </xsl:template>

  <xsl:template match="a:category" mode="categories">
    <xsl:value-of select="@term"/>
    <xsl:if test="position() != last()">
      <xsl:text> | </xsl:text>
    </xsl:if>
  </xsl:template>

  <xsl:template match="*[@type='text']|*[not(@type)]" mode="text-construct">
    <xsl:value-of select="node()"/>
  </xsl:template>

  <xsl:template match="*[@type='xhtml']" mode="text-construct">
    <xsl:copy-of select="node()"/>
  </xsl:template>

</xsl:stylesheet>

何よりもまず、XHTML 名前空間が 2 回宣言されていることに注目してください。最初の宣言では、接頭辞が使用されています。XPath 1.0 では名前空間に含まれる要素と属性にアクセスするために、接頭辞を使用しなければならないためです。2 回目の宣言は、接頭辞なしで出力を生成するためのものです (したがって、デフォルト名前空間形式を使用する必要があります)。デフォルトでは、XSLT プロセッサーはスタイルシートに含まれる名前空間宣言を出力にコピーします。ここでは、exclude-result-prefixes 属性を使用して、出力に余計な接頭辞が含まれないようにしています。次に、XHTML 1.1 を生成するために、必要な文書型宣言を組み込んだ xsl:output 命令を記述します。

Atom のテキスト構成体は、text-construct モードのテンプレート一式を使用して処理されます。プレーン・テキストの構成体と XHTML 構成体は、それぞれ別のテンプレートによって処理が行われるため、属性が突き合せられます。リストを見るとわかるように、プレーン・テキストでは xsl:value-of を使用して単一の文字データ出力ノードを生成するのに対し、XHTML では xsl:copy-of を使用して XHTML 出力にマークアップを逐語的に反映するというだけの単純な違いです。type="html" の場合、この変換における特殊なサポートはありません。このタイプの構成体を有用な形で処理するのは極めて困難です。特に XSLT では、マークアップが変更され、整形式でない可能性すらあるため、その処理は困難を極めます。この変換では、そのようなテキスト構成体はプレーン・テキストとして逐語的に出力に渡されます (これは、デフォルトの XSLT テンプレートによる結果です。text-construct モードでは、このデフォルトのテンプレートは変更していません)。XHTML 出力の場合、これは、出力を読み取るために使用されるブラウザーで、タグが表示方法として解釈されるのではなく、そのまま表示されることを意味します。そうなると、当然 HTML 言語を知らない誰にとっても混乱の種となります。

メタデータ・ブロック内に出現するリンクとカテゴリーのリストも、モジュール単位でレンダリングするためのモードを使用します。このようにすれば、Atom の拡張機能であっても、同じ方法で極めて簡単にフィールドを追加することができます。

出力には xml:lang="en" が指定されていることに注目してください。これを指定した理由は、XSLT では、ラベルなどに英語の名前 (例えば、Categories) をハード・コーティングしているためです。これらのラベルを自分が使用する言語に対応させたいと考え、言語宣言を変更するか、何らかの自動国際化手法を使用する場合でも、残念ながら、フィード内での表示言語が文書全体の言語として宣言された言語と一致しない可能性に対処しなければならなくなります。これは難しい問題であり、このチュートリアルの範囲を遥かに越えています。ただし、言語を完全に省略するという方法を選ぶこともできます。一方で、すべての情報が 1 つの言語で記述されているケースが多いので、その場合は言語を指定できるというだけでなく、必ず指定するべきです。

XHTML 変換の出力

atom-with-xhtml-1.xml (「ダウンロード」を参照) は、リスト 5 (atom-with-xhtml.xml) とまったく同じ内容に、リスト 6 (atom2xhtml.xslt.xml) を使用してレンダリングするための PI を追加したものです。ブラウザーでの表示結果を図 3 に示します。

図 3. リスト 5 にリスト 6 を適用した場合のブラウザー出力
ブラウザーに表示された atom-with-xhtml-1.xml

コンテンツの構成体

Atom の content 要素には、前述のすべてのテキスト構成体を使用できるだけでなく、他にも使用できるものがあります。他のテキスト要素は短いテキスト部分を格納するように意図されている一方、content は、おそらくウェブログ・エントリーの全内容を格納するように意図されています。この理由から、Atom ではこの要素に柔軟性を追加しています。まず、この要素の type 属性は、あらゆるインターネット・メディア・タイプに設定することができます。メディア・タイプが、何らかの特定のルールに従ったテキスト・メディア・タイプであると考えられる場合は、そのテキストを要素の本体に挿入します。メディア・タイプが、XML メディア・タイプであると考えられる場合は、任意の語彙の XML コンテンツを直接要素の本体に収容することができます。その他すべてのメディア・タイプについては、コンテンツを Base64 でエンコードする必要があります (これに該当するのは、コンテンツが写真や音声ファイルの場合です)。このチュートリアルでは、テキストおよび XML メディア・タイプだけを取り上げます。

content 要素では、src 属性を使用して外部にあるコンテンツを指すこともできます。この属性には外部コンテンツの URI を指定します。これを指定した場合、content 要素は空でなければなりません。この構成体は、HTML や XHTML の object 要素と同様です。

リスト 7 (atom2xhtml-1.xslt.xml) は、リスト 6 (atom2xhtml.xslt.xml) をベースに、テキストおよび XML コンテンツ・メディア・タイプのサポートを追加したものです。

リスト 7. リスト 6 を更新して、テキストおよび XML メディア・タイプのコンテンツをサポートするようにした XSLT (atom2xhtml-1.xslt.xml)
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:a="http://www.w3.org/2005/Atom"
  xmlns:xhtml="http://www.w3.org/1999/xhtml"
  xmlns="http://www.w3.org/1999/xhtml"
  exclude-result-prefixes="a xhtml">

  <xsl:output method="xml" encoding="utf-8"
              doctype-public="-//W3C//DTD XHTML 1.1//EN"
              doctype-system="http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"/>
  <xsl:template match="*"/><!-- Ignore unknown elements -->
  <xsl:template match="*" mode="links"/>
  <xsl:template match="*" mode="categories"/>

  <xsl:template match="a:feed">
<html xml:lang="en">
  <head>
    <title><xsl:value-of select="a:title"/></title>
  </head>
  <body>
    <h1><xsl:apply-templates select="a:title" mode="text-construct"/></h1>
    <xsl:apply-templates/>
    <p>Feed ID: <xsl:value-of select="a:id"/></p>
    <p>Feed updated: <xsl:value-of select="a:updated"/></p>
    <xsl:apply-templates/>
  </body>
</html>
  </xsl:template>

  <xsl:template match="a:summary">
    <div class="summary">
      <xsl:apply-templates select="." mode="text-construct"/>
    </div>
  </xsl:template>

  <xsl:template match="a:content">
    <div class="content">
      <xsl:apply-templates select="." mode="text-construct"/>
    </div>
  </xsl:template>

  <xsl:template match="a:entry">
    <div class="entry">
      <h2><xsl:apply-templates select="a:title" mode="text-construct"/></h2>
      <div class="id">Entry ID: <xsl:value-of select="a:id"/></div>
      <div class="updated">Entry updated: <xsl:value-of select="a:updated"/></div>
      <div class="links">
        <xsl:text/>Links: <xsl:apply-templates select="a:link" mode="links"/>
      </div>
      <div class="categories">
        <xsl:text>Categories: </xsl:text>
        <xsl:apply-templates select="a:category" mode="categories"/>
      </div>
      <xsl:apply-templates/>
    </div>
  </xsl:template>

  <xsl:template match="a:link" mode="links">
    <a href="{@href}">
      <xsl:value-of select="@rel"/>
      <xsl:if test="not(@rel)">[generic link]</xsl:if>
      <xsl:if test="@type">
        <xsl:text> (</xsl:text><xsl:value-of select="@type"/><xsl:text>): </xsl:text>
      </xsl:if>
      <xsl:value-of select="@title"/>
    </a>
    <xsl:if test="position() != last()">
      <xsl:text> | </xsl:text>
    </xsl:if>
  </xsl:template>

  <xsl:template match="a:category" mode="categories">
    <xsl:value-of select="@term"/>
    <xsl:if test="position() != last()">
      <xsl:text> | </xsl:text>
    </xsl:if>
  </xsl:template>

  <xsl:template match="*[@type='text']|*[not(@type)]" mode="text-construct">
    <xsl:value-of select="node()"/>
  </xsl:template>

  <xsl:template match="*[@type='xhtml']" mode="text-construct">
    <xsl:copy-of select="node()"/>
  </xsl:template>

  <!-- Handle content elements with external data -->
  <xsl:template match="a:content[@src]" mode="text-construct">
    <!-- Use the XHTML object element -->
    <object data="{@src}" type="{@type}">Unable to render object</object>
  </xsl:template>

  <!-- Handle text media types for content elements -->
  <xsl:template
    match="a:content[not(@src)][starts-with(@type, 'text/')]"
    mode="text-construct">
    <xsl:value-of select="node()"/>
  </xsl:template>

  <!-- Handle XML media types for content elements -->
  <xsl:template
    match="a:content[not(@src)][substring-after(@type, '/') = 'xml'
           or starts-with(substring-after(@type, '/'), '+') = 'xml']"
    mode="text-construct">
    <!-- Just copy the XML over.  If mixed mode XHTML is not supported
         this might cause problems -->
    <xsl:copy-of select="node()"/>
  </xsl:template>

</xsl:stylesheet>

HTML 4.01 に変換する

すべての Web ユーザー・エージェントが XHTML 1.1 を処理するとは限りません。Atom 1.0 から HTML 出力を生成しなければならない場合もあります。この芸当を行うのが、リスト 8 (atom2html4.xslt.xml) です。ここには、テキスト構成体と XHTML テキスト構成体のサポートが組み込まれていますが、メディア・タイプによって表現されるコンテンツ構造のサポートはありません。ご想像のとおり、この XSLT はリスト 6 と非常によく似たものです (atom2xhtml.xslt.xml)。メディア・タイプで表現したコンテンツ構造のサポートを追加するには、リスト 7 のコードをコピーして、それぞれの困難な場合の対処方法に応じて (例えば、コンテンツにリテラル XML を組み込むなど)、その内容を変更すればよいのです。

リスト 8. Atom フィードの HTML 4 ビューを提供する XSLT 変換 (atom2html4.xslt.xml)
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:a="http://www.w3.org/2005/Atom"
  xmlns:xhtml="http://www.w3.org/1999/xhtml" 
  exclude-result-prefixes="a xhtml">

  <xsl:output method="html" version="4.01" encoding="iso-8859-1"
              doctype-public="-//W3C//DTD HTML 4.01//EN"
              doctype-system="http://www.w3.org/TR/html4/strict.dtd"/>

  <xsl:template match="*"/><!-- Ignore unknown elements -->
  <xsl:template match="*" mode="links"/>
  <xsl:template match="*" mode="categories"/>

  <xsl:template match="a:feed">
<html>
  <head>
    <title><xsl:value-of select="a:title"/></title>
  </head>
  <body>
    <h1><xsl:apply-templates select="a:title" mode="text-construct"/></h1>
    <xsl:apply-templates/>
    <p>Feed ID: <xsl:value-of select="a:id"/></p>
    <p>Feed updated: <xsl:value-of select="a:updated"/></p>
    <xsl:apply-templates/>
  </body>
</html>
  </xsl:template>

  <xsl:template match="a:summary">
    <div class="summary">
      <xsl:apply-templates select="." mode="text-construct"/>
    </div>
  </xsl:template>

  <xsl:template match="a:content">
    <div class="content">
      <xsl:apply-templates select="." mode="text-construct"/>
    </div>
  </xsl:template>

  <xsl:template match="a:entry">
    <div class="entry">
      <h2><xsl:apply-templates select="a:title" mode="text-construct"/></h2>
      <div class="id">Entry ID: <xsl:value-of select="a:id"/></div>
      <div class="updated">Entry updated: <xsl:value-of select="a:updated"/></div>
      <div class="links">
	<xsl:text/>Links: <xsl:apply-templates select="a:link" mode="links"/>
      </div>
      <div class="categories">
	<xsl:text>Categories: </xsl:text>
	<xsl:apply-templates select="a:category" mode="categories"/>
      </div>
      <xsl:apply-templates/>
    </div>
  </xsl:template>

  <xsl:template match="a:link" mode="links">
    <a href="{@href}">
      <xsl:value-of select="@rel"/>
      <xsl:if test="not(@rel)">[generic link]</xsl:if>
      <xsl:if test="@type">
	<xsl:text> (</xsl:text><xsl:value-of select="@type"/><xsl:text>): </xsl:text>
      </xsl:if>
      <xsl:value-of select="@title"/>
    </a>
    <xsl:if test="position() != last()">
      <xsl:text> | </xsl:text>
    </xsl:if>
  </xsl:template>

  <xsl:template match="a:category" mode="categories">
    <xsl:value-of select="@term"/>
    <xsl:if test="position() != last()">
      <xsl:text> | </xsl:text>
    </xsl:if>
  </xsl:template>

  <xsl:template match="*[@type='text']|*[not(@type)]" mode="text-construct">
    <xsl:value-of select="node()"/>
  </xsl:template>

  <xsl:template match="*[@type='xhtml']" mode="text-construct">
    <xsl:apply-templates select="node()" mode="xhtml2html"/>
  </xsl:template>

  <xsl:template match="*" mode="xhtml2html">
    <xsl:element name="{local-name()}">
      <xsl:apply-templates select="@*|node()" mode="xhtml2html"/>
    </xsl:element>
  </xsl:template>

  <!-- omits comments and PIs -->
  <xsl:template match="@*|text()" mode="xhtml2html">
    <xsl:copy/>
  </xsl:template>

</xsl:stylesheet>

リスト 6 と異なる点は、まず、名前空間の宣言です。上記リストの場合、出力される要素は通常の HTML になるため、デフォルト名前空間の宣言はありません。xsl:output も、HTML 4 を生成するための適切な XSLT イディオムを使用するように変更されています。最後の変更点は、変換の終わり近くにあり、以前は 1 つのテンプレートでテキスト構成体を処理していましたが、今では 3 つになっています。この変換プロセスが前よりも複雑になっている理由は、名前空間を省略して他の XML 主義を回避しなければならないためです。最後の xhtml2html モードに設定された 2 つのテンプレートは、ID 変換と同様ですが、名前空間を除去して要素、属性、テキストだけを逐語的に出力にコピーします。厳密に言うと、言語宣言と ID 宣言の XHTML イディオムも HTML 形式に変更する必要があるかもしれませんが、フィード内の XHTML コンテンツにこれらのイディオムがあることはめったにありません。


Atom を生成する

前のセクションでは、XSLT による Atom の読み込み手法を紹介しました。このセクションでは、大抵の場合に役立つ Atom フィードの作成手法を説明します。

XHTML から Atom を抽出する

Atom フィードは一般に、単なるコンテンツ・メタデータの集まりであり、コンテンツの主要な XML フォーマットと言えば、XHTML が挙げられることから、皆さんは XHTML から直接 Atom を生成したいと思うことがあるかもしれません。スキーマ、あるいは慣例では、XHTML は Atom フィードに必要となるほぼあらゆるものをサポートするオプションの構造をカバーします。リスト 9 (xhtml2atom.xslt) の変換では、妥当な XHTML 文書の URL のリストを受け取り、これらの文書を構文解析して、各 URL のエントリーからなる Atom フィードを生成します。

リスト 9. XHTML ファイルのリストから Atom フィードを生成するための変換 (xhtml2atom.xslt)
<?xml version="1.0" encoding="utf-8"?>
<xsl:transform  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xhtml="http://www.w3.org/1999/xhtml"
  xmlns:a="http://www.w3.org/2005/Atom"
  xmlns="http://www.w3.org/2005/Atom"
  exclude-result-prefixes="a xhtml">

  <xsl:output method="xml" indent="yes"/>
  <xsl:param name="feed-id" select="'http://www.example.org/dw-feed'"/>
  <xsl:param name="feed-title" select="'Sample Atom feed'"/>
  <xsl:param name="feed-updated" select="'2005-11-07T12:00:00Z'"/>
  <xsl:param name="main-link" 
      select="'http://www.ibm.com/developerworks/'"/>
  <xsl:param name="entries-author" select="'James Snell'"/>

  <xsl:template match="/">
<feed xml:lang="en">
  <id><xsl:value-of select="$feed-id"/></id>
  <title><xsl:value-of select="$feed-title"/></title>
  <updated><xsl:value-of select="$feed-updated"/></updated>
  <author><name><xsl:value-of 
      select="$entries-author"/></name></author>
  <link href="{$main-link}"/>
  <xsl:apply-templates/>
</feed>
  </xsl:template>

  <xsl:template match="link">
    <xsl:apply-templates select="document(@href)" mode="parse-xhtml">
      <xsl:with-param name="entry-href" select="@href"/>
    </xsl:apply-templates>
  </xsl:template>

  <xsl:template match="/" mode="parse-xhtml">
    <xsl:param name="entry-href"/>
    <entry>
      <xsl:apply-templates select="/*/xhtml:head" mode="parse-xhtml">
	<xsl:with-param name="entry-href" select="$entry-href"/>
      </xsl:apply-templates>
    </entry>
  </xsl:template>

  <xsl:template match="xhtml:head" mode="parse-xhtml">
    <xsl:param name="entry-href"/>
    <id><xsl:value-of select="$entry-href"/></id>
    <title><xsl:value-of select="xhtml:title"/></title>
    <updated><xsl:value-of select="$feed-updated"/></updated>
    <link href="{$entry-href}" type="application/atom+xml"/>
    <xsl:apply-templates 
       select="(//xhtml:body//xhtml:p)[1]" mode="parse-xhtml"/>
  </xsl:template>

  <xsl:template match="xhtml:p" mode="parse-xhtml">
    <summary type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
	<xsl:copy-of select="node()"/>
      </div>
    </summary>
  </xsl:template>

</xsl:transform>

このリストでは、最初に 5 つの主要なパラメーターを定義しています。これらのパラメーターには、フィード全体にとって重要なフィールドが含まれており、それらのデフォルト値としては、この変換の使用例に基づく値が設定されています。次のセクションを見ると、これらのデフォルト値を変更する方法がわかるはずです。パラメーター値は変換の中で更新するか、パラメーターを上書きすることによって更新することになります。この変換のソース文書は links 要素であり、そこには 1 つ以上の links 要素が含まれる場合と links 要素が含まれない場合があります。これらの要素が、match="link" が設定されたテンプレートによって突き合わせられます。このテンプレートは、href 属性に指定された文書をロードした後、その URL のエントリーを書き込むために parse-xhtml モードに移行して、後でエントリーの「self」へのリンクで使用するためにロードした URL を渡します。

parse-xhtml モードでは、プッシュ・スタイルの XSLT 手法を使ってはいますが、もう少し直接的に処理を命令しています。その理由は、ここでは単に、各文書から明確にマッピングされた少数の情報を取得するだけだからです。各エントリーに 1 つのリンクがあり、そのリンクは渡されたentry-href を使用することに注目してください。それぞれのリンクが XHTML 文書であることはわかっているので、リンクの type 属性はそれに応じて設定することができます。次に、summary 要素で使用するために、XPath として (//xhtml:body//xhtml:p)[1] を使用して文書の本体から 最初のパラグラフを取得します。match="xhtml:p" を設定したテンプレートが、XHTML テキスト構成体に含まれるこの要素のコンテンツを再帰的にコピーし、デフォルト名前空間をテキスト構成体の本体に含まれる XHTML に切り替えます。

Atom ジェネレーターの動作

リスト 10 (xhtml-urls.xml) は、XHTML URI の単純なリストです。この例では、Atom 1.0 に関する 3 つの IBM developerWorks 記事の詳細を、Atom フィードに取り込みます。

リスト 10. Atom フィードを生成するための XHTML ファイルのリスト (xhtml-urls.xml)
<links>
  <link href="http://www-128.ibm.com/developerworks/xml/library/x-atom10.html"/>
  <link href="http://www.ibm.com/developerworks/xml/library/x-extatom1/"/>
  <link href="http://www-128.ibm.com/developerworks/xml/library/x-extatom2.html"/>
</links>

図 4 に、実行中の変換を示します。

図 4. リスト 10 にリスト 9 を適用するコマンドライン・セッション
コマンドラインによる Atom 文書での XSLT 呼び出し

いつでもパラメーターの値を変更して、主要なフィールドを調整することができます。例えば、4Suite を使用してフィードのタイトルを変更するには、以下のようにします。

4xslt -D feed-title="IBM dW on Atom" xhtml-urls.xml xhtml2atom.xslt

日時を設定する

お気付きかもしれませんが、上記の変換 (リスト 9) では日時をハードコーディングしました。けれども、実際には現在の日時が必要になります。ここで扱っている平凡な XSLT では、現在の日時を設定することはできませんが、コミュニティーが XSLT 拡張機能を標準化した EXSLT を使用すれば、設定することができます。以下のスニペット (リスト 11) は、リスト 9 の先頭部分の代わりとなるコードです。これを見ると、現在の日時を設定する方法がわかります。

リスト 11. 現在の日時を設定するリスト 9 の先頭部分のバリエーション
<?xml version="1.0" encoding="utf-8"?>
<xsl:transform  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xhtml="http://www.w3.org/1999/xhtml"
  xmlns:a="http://www.w3.org/2005/Atom"
  xmlns="http://www.w3.org/2005/Atom"
  xmlns:date="http://exslt.org/dates-and-times"
  exclude-result-prefixes="a xhtml">

  <xsl:output method="xml" indent="yes"/>
  <xsl:param name="feed-id" select="'http://www.example.org/dw-feed'"/>
  <xsl:param name="feed-title" select="'Sample Atom feed'"/>
  <xsl:param name="feed-updated" select="$now"/>
  <xsl:variable name="now" select="date:date-time()"/>

上記コードは、最後の 2 行が重要です。now 変数が定義される前に使用されていることは気にしないでください。これは XSLT では許容されることで、変数は適切な順序で解決されます。また、date 接頭辞のために追加されている名前空間宣言にも目を向けてください。この日時設定コードでリスト 9 を更新したファイルは、xhtml2atom-1.xslt (「ダウンロード」を参照) です。このファイルは、EXSLT の日時モジュールをサポートする XSLT プロセッサーで機能するように作られています。4Suite のプロセッサーを含め、多数のスタンドアロン・プロセッサーが EXSLT の日時モジュールをサポートしていますが、(この記事の原文が公開された 2005年の時点では) 残念ながら Mozilla では (したがって Firefox では) サポートしていません。


実用上の注意事項

このセクションでは、Atom を XSLT で処理する際にとりわけ役立つ実用上の所見をまとめて紹介します。

ベース URI を処理する

多くの XML フォーマットと同じく、Atom ではユーザーがベース URI を設定し、文書内の相対 URI はそのベース URI に対して解決されるようにすることができます。ベース URI を設定するには、xml:base 属性を使用します。リスト 1 では、feed 要素でこの属性を使用しましたが、この feed 要素に対してリスト 6 のような変換を適用したとしたら、XHTML には /blog のようなリンクが含まれることになります。Atom では http://www.example.org がベース URI として有効になるため、完全な URI は http://www.example.org/blog となるはずです。問題は、生成された XHTML を URI http://test.example.org でホストするとしたら、相対リンクが http://test.example.org/blog に展開されて、もはや同じリンクではなくなってしまうことです。

xml:base 属性を Atom から XHTML にコピーするだけでこの問題に対処できればよいのですが、この属性はあいにく XHTML 1.0 や XHTML 1.1では無効です。この属性は XHTML 2.0 のドラフトでは有効なものの、この仕様はまだ策定中です (訳注: この記事の原文が執筆された 2005年時点での話です)。Mozilla ブラウザーは XHTML 1.x でも xml:base を探すとは言え、これは標準の動作ではないので避けてください。解決方法となるのは、XHTML の base 要素を作成することです。リスト 1 のように、Atom ソースの最上位レベル (つまり、feed 要素) に 1 つの xml:base 属性があれば、事が遥かに容易になります。リスト 12 に、リスト 6 の該当するテンプレートを更新して、ベース URI を処理するようにしたスニペットを記載します。

リスト 12. ベース URI をサポートするように更新された Atom feed 要素を処理するテンプレート (atom2xhtml.xslt-1.xml から抜粋)
<xsl:template match="a:feed">
<html xml:lang="en">
  <head>
    <title><xsl:value-of select="a:title"/></title>
    <base href="{@xml:base}"/>  <!-- handle Base URI -->
  </head>
  <body>
    <h1><xsl:apply-templates select="a:title" mode="text-construct"/></h1>
    <xsl:apply-templates/>
    <p>Feed ID: <xsl:value-of select="a:id"/></p>
    <p>Feed updated: <xsl:value-of select="a:updated"/></p>
    <xsl:apply-templates/>
  </body>
</html>
</xsl:template>

このベース URI コードでリスト 6 を更新したファイルは、atom2xhtml.xslt-1.xml (「ダウンロード」を参照) です。

作業結果に対する妥当性検証を行う

このチュートリアルでは、Atom フォーマットを読み取る方法であれ、書き込む方法であれ、Atom 1.0 の処理方法について多くを学びました。対象となる Atom 文書の妥当性が確実であれば、Atom の処理はなおさら容易になるでしょう。けれども、誰にでも間違いはあり、Atom 文書の正確さを確実にするには、文書を検証するより他にありません。少なくともプロジェクトのテスト・フェースで Atom の入力と出力の妥当性検証を行って、本番環境で問題が発生した場合に容易に妥当性検証に立ち返れるようにすることをお勧めします。ある程度のテストは、仕様に関連付けられた RELAX NG スキーマを使用して行うことが可能です (「参考文献」を参照)。その場合には、Compact Syntax を読み取る RELAX NG プロセッサーか、Compact Syntax から XML 構文への変換に使用できるツールが必要になります。

W3C のオンライン妥当性検証フォームを使用する

RELAX NG では、Atom 文書に課せられるすべての制約事項をチェックすることはできません。幸い、Atom コミュニティーが妥当性検証ツールを開発し、W3C がフォーム・ベースの Atom 妥当性検証用インターフェースをホストしています。このフォームには、オンラインでホストされている Atom 文書のアドレスを入力する (「Validate by URL (URL による妥当性検証)」) か、文書のコンテンツを貼り付ける (「Validate by Direct Input (直接入力による妥当性検証」) ことができます。前者の方法を使用する場合、バリデーターは Atom 文書に応じた Web サーバーのセットアップもチェックします。例えば、サーバーがサポートする文字コードが、文書でレポートされている文字コードと一致するかどうかをチェックするなどです。また、文書を HTTP POST または SOAP で送信して妥当性検証を行うこともできます。図 5 に、このバリデーターを使用したブラウザー・セッションの例を示します。

図 5. W3C フィード・バリデーターを使用したブラウザー・セッション
W3C フィード・バリデーターの実行結果

W3C のバリデーターは、元々 feedvalidator.org でホストされていたコードをベースとしています。W3C では 2004年 11月に独自のサービスを開始しましたが、この記事を執筆した 2005年の時点では、そのシステムにはまだ不備があります。皆さんがこの記事を読む頃には、これらの不備が解消されて、安心して W3C フィード・バリデーターを使用できるようになっていることを願います。


まとめ

要約

このチュートリアルでは、XSLT 1.0 を使用して Atom 1.0 を処理する方法を学びました。具体的には、以下の方法を学びました。

  • Atom フォーマットの基本要素にアクセスする
  • Atom のリンクを解釈してリンクにアクセスする
  • Atom の作成者およびカテゴリー情報を解釈してアクセスする
  • Atom フィードの簡単な要約であるティッカー・テープを生成する
  • ブラウザーまたはスタンドアロン XSLT プロセッサーでのティッカー・テープ変換をセットアップする
  • プレーン・テキストの Atom テキスト・フィールドを処理する
  • XHTML の Atom テキスト・フィールドを処理する
  • Atom フィードを XHTML および HTML 4 に変換する
  • XHTML から情報を抽出して Atom フィードに取り込む
  • Atom フィードに現在の日時を設定する
  • Atom のベース URI 情報を XHTML 出力でも保持する
  • RELAX NG 仕様および W3C バリデーターで Atom 文書を検証する

このチュートリアルで学んだ知識を基にすれば、さまざまな処理機能を作成できるはずです。場合によっては、XHTML 1.0 だけで十分必要を満たせます。その一方、EXSLT や、さらにはアプリケーションによる処理が必要になることもありますが、適切に設計された XSLT では Atom をどこまで処理できるかについて、それなりに理解していただけたことを願います。


ダウンロード

内容ファイル名サイズ
Sample applicationx-atomxsl-tutorial-files.zip11KB

参考文献

学ぶために

製品や技術を入手するために

  • Atom フィードで developerWorks の最新情報を入手してください。事前定義されたフィードを使用することも、独自のカスタム・フィードを定義することもできます。
  • W3C Feed Validation Service を使用して、Atom 文書を検証してください。このバリデーターは、feedvalidator.org の技術をベースとしています。
  • チュートリアルで使用したサンプルを実際に実行してみてください。ブラウザーのサンプルは、Firefox でテストしました。Firefox は、Mozilla をベースとした評判の高い無料の Web ブラウザーで、Windows、Mac OS X、Linux およびその他のプラットフォームで使用できます。スタンドアロンの XSLT 処理は、4Suite を使用してコマンドラインでテストしました。

議論するために

  • Atom and RSS forumで、Atom、RSS、およびその他のシンジケーションに関するヒント、技、答えを見つけてください。
  • developerWorks blogs から developerWorks コミュニティーに加わってください。

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=XML
ArticleID=837576
ArticleTitle=XSLT を使用して Atom 1.0 を処理する
publish-date=09272012