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に実データの運搬という役割を与えること自体に疑問を持っている人もいるぐらいなので、なにやら世の中はなかなか混乱しているようだ。
今度アリゲーターごとの対応方法を研究してみるか。
http://yudai.arielworks.com/memo/2004/10/12/045601.trackback
末尾に「1 + 6」の計算結果を繋げて下さい。例えば計算結果が「17」の場合、「045601.trackback17」です。これは機械的なトラックバックスパムを防止するための措置です。