content:encodedを実装しようせっかくなので、content:encodedをうちのRSSに実装しようと思ったのだけれど、CDATAセクションの生成方法が思いつかなかった。仕様書を読む限り、実体参照に置き換えるだけでもかまわないようだけど、CDATAの方が綺麗で良いかなぁ、と思う。XSLTでうまく変換する方法ないかな。
ところで、個人的に気になるのが、どういう経緯でエスケープする事になってしまったのか、だ。XMLなのだから語彙を混ぜてしまえば良いのに、わざわざCDATAセクションで括って文字列として扱う事になっている。たとえば、次のような感じだ。
<content:encoded><![CDATA[<p>What a <em>beautiful</em> day!</p>]]></content:encoded>
よく考えると、この例のp要素は宙に浮いてしまっている。名前空間について何も述べられていないので、もしかしたらXHTML以外の語彙である可能性がある。
仕様書を読み進めていくと、content:formatでフォーマットを指定できるとは書いてある。随分回りくどいことをするなぁ、と思ったのだが、どうやらこれはcontent:encoded内のデータがXML以外の規格でも(例えばHTML4.1)対応できるように考慮されているようだ。
しかし、ここでさらに気になるのは、内容データが複数語彙で構成されていたらどうするのだろう、と言うことだ。XHTML+SVGとか言われたら混乱しそうな気がする。たしかにSGML系のデータも取り込めるのは便利かも知れないが、今更感が強い気がする。十分に整備されているXMLの名前空間を使った方が便利というか、DOMなりXSLTなりで一発変換できるし、RSSを処理するプログラムも語彙の判別が楽だろう。XMLはXMLで完結していた方が良いんではないだろうか。
もう決着した話題ですが、すこしだけ捕捉を。
まず、「RSSの使い勝手が下がるかも」は完全に私の勘違いです。どういう訳かcontent:encodedがrss:description内に含まれるのかと思っていました。
昨日の日記にもコメント入れましたが、tDiary の makerss.rb で生成する RSS には、<item> の中に <description> は無いはずです。すくなくとも私の tDiary2.0.0で作成されているものにはありません。 ちゃんと本文を入れるべき<content:encoded>に全文を入れているので使い方は間違っていないと思います。
このツッコミを見て「おや?」と思い、仕様書を確認したところ、「うわー勘違いしてたよー、content:encoded内は実データだ」と思い、思わず最初の「暗黙の了解?」まで破棄してしまったのですが、その後の経過を見ると、件のRSSにはrss:descriptionも含まれていたようです。
なお、件のものは content:encoded は使わず、description だけ表示していました。
このツッコミを見ると、やはり本文のほとんどがrss:description内に含まれていたと考えられます。ただ、content:encodedも含まれていたようで、たまたまこの部分のみが脳に引っかかっていたため、反射的に「しくじった」と思いこんでしまったようです。
description要素は500byte以降は表示しないようになってる。ただ、500byteが、サブタイトル単位となっているようで、ここのように、各章を比較的細切れにしている場合はどうしても全部の情報が含まれてしまう。
に有るとおり、今回の発端は、コーディングスタイルの関係でたまたまrss:description内にもほぼ全文が格納されてしまった事だと考えられます。
現物が404で確認できないため確かなことは言えないのですが、「暗黙の了解?」は破棄する必要が無かったのかも知れません。とはいえ、今回はすでに解決済みであり、指向性の高い文章をサルベージしてももはや意味がないのでそのままにしておきます。
一般化した要旨だけ抜き取るとしたら、
という事になると思います。
最後に、あやふやな行動で混乱を発生する一因になってしまった事をお詫び致します。今回は私自身も色々と勉強になりました。ありがとうございました。
content:encodedを実装しよう・その2実装編。
テンプレートを使ってエスケープする方法も考えて、実際にXSLを書いてみたのだけれども、あまり綺麗な感じにならなかったので、xsl:textを使ってベタに<![CDATA[を書いてしまう作戦に切り替えた。
が、やはり名前空間が問題に。XSL自体は名前空間をもの凄く大切に思っているので、
<content:encoded>
<xsl:text disable-output-escaping="yes"><![CDATA[</xsl:text>
<xsl:copy-of select="./sdf:body/node()"/>
<xsl:text disable-output-escaping="yes">]]></xsl:text>
</content:encoded>
などと書くと、./sdf:body/node()が全てxh:pなどと接頭辞付きで出力される(ここで接頭辞xhはXHTMLにマップされている)。
<content:encoded><xh:p>ほげほげ</xh:p></content:encoded>
だからといってexclude-result-prefixes="xh"などとすれば、今度は各要素にxmlns="http://www.w3.org/1999/xhtml"が付加されてこれまた汚くなる。
<content:encoded><p xmlns="http://www.w3.org/1999/xhtml">ほげほげ</p></content:encoded>
これ、パースする応用ソフト側はどうやって対応しているのかなぁ、と思いつつも、既存のRSSを見る限り接頭辞も名前空間宣言も付いていないので、そうした方がいいのだろう。
しょうがないので接頭辞無しの要素を出力するようにテンプレートを書いてみた。XSLプロセッサを少しだけ騙してあげればよい。
<content:encoded>
<xsl:text disable-output-escaping="yes"><![CDATA[</xsl:text>
<xsl:apply-templates select="./sdf:body/node()" mode="toEncoded"/>
<xsl:text disable-output-escaping="yes">]]></xsl:text>
</content:encoded>
<xsl:template match="*" mode="toEncoded">
<xsl:element name="{local-name()}">
<xsl:apply-templates select="@*" mode="toEncoded"/>
<xsl:apply-templates mode="toEncoded"/>
</xsl:element>
</xsl:template>
<xsl:template match="@*" mode="toEncoded">
<xsl:copy-of select="."/>
</xsl:template>
これでとりあえずは思い通りの結果が得られた。
<content:encoded><p>ほげほげ</p></content:encoded>
やはり、どこか釈然としないところがあるなぁ。content:formatでDTDのURIを渡されてもXML的には無意味だし、DOMやXSLTがネイティブに扱えないのはかなり腐っているような気がする。
一瞬考えればみんな同じようなことを思うらしく、だいぶ前から問題が指摘されているようだ。さらに言えば、RSSに実データの運搬という役割を与えること自体に疑問を持っている人もいるぐらいなので、なにやら世の中はなかなか混乱しているようだ。
今度アリゲーターごとの対応方法を研究してみるか。