document関数の例の第一回は、最も単純なdocument(絶対URI) というパターンの例を、RSSの再利用という形で紹介します。
document(絶対URI)の場合、そのURIであらわされるリソースのXMLノードツリーのルートノードのみを含むノード集合が返されます。それだけですので別に例示する程の話でもありませんが、ちょうどagendaの最新版を整形しているXSLTスタイルシートで使用しているので急遽書いてみることにしました。さて:
Weblogの最新版では、最新の記事一つだけを紹介し、それ以前の数点は「最近の記事一覧」としてアンカーと概要のみを掲載することにしました。dive into markの「older posts」の真似です。
「最近の記事一覧」のアンカーリストは、RSS文書から引っ張ってきたデータをHTMLに変換する形で、XSLT(スタイルシートとプロセッサ)に行わせます。
<xsl:template name="olderPosts">
<xsl:variable name="rss.nodeset"
select="document('http://members.jcom.home.ne.jp/jintrick/Personal/putdata.xml')" />
<dl>
<xsl:for-each
select="$rss.nodeset/descendant::rss:item[string(child::slash:section) = 'agenda']">
<dt>
<a href="{@rdf:about}">
<xsl:value-of select="string(child::rss:title)" />
</a>
</dt>
<dd>
<dl>
<dt>更新日時</dt>
<dd>
<xsl:value-of select="string(child::dc:date)" />
</dd>
<dt>概要</dt>
<dd>
<xsl:value-of select="string(child::rss:description)" />
</dd>
</dl>
</dd>
</xsl:for-each>
</dl>
</xsl:template>
これを任意の位置でcall-templateするだけです。というわけで、XSLTの話題として面白くもなんともありませんというか、RSSの再利用の話ですかこれは。他のサブサイトのホームページで、最近更新した文書をこのような形で紹介すると便利かもしれません。
他に、document関数を利用して、サイト全体のRSSをサブサイトのRSSに分割したりできます。その場合、サブサイトを識別する何らかの要素がRSS文書の各item要素内に必要です。前述の例では、サイト「Personnel」の更新情報としてのRSSの中に、サブサイト「agenda」の更新情報が含まれており、サブサイト「agenda」の更新アイテム(主語)については、slash dotモジュールを利用して、slash:section要素(述語)にagendaというテキストノード(目的語)を入れて識別しています。
XSLT1.0 のdocument関数の定義をはっきりさせる試み。
仕様書のdocument関数の説明が曖昧で分かりづらいと思われたので、適当に意訳してみました。間違った解説、不十分な解説が多いのも理由です。
尚、ノード集合は {} (一対のカーリブラケット)で表記し、各ノードはその中にカンマで区切って列挙しています。
もう少し短くしますと:
因みにこのケースについてきちんと説明している解説を見たことがありません。
docuemnt(ノード集合)の例に続きます。
docuemnt(絶対URI)の例に続きます。
私はまずこの方法は使いません。最初からstring関数で文字列に変換しておきます。ややこしいからエラーにしてしまえば良いのに。
それぞれの例については後ほど(長すぎるので)。
DOMインターフェイス等を使ってXMLノードツリーのちょっとした検索をする場合に、無駄な変数の宣言を避け、その検索にのみ使用する変数を全て、その検索処理を行う関数の外部からは参照できない局所変数にし、さらにその関数自体も無名関数を使ってみようという試みです。
簡便化の為、XMLノードツリーは擬似的に単なる配列(Arrayオブジェクト)にして例示します。
var ary = [0, [1, 1, [2, 'it', [3,3]]]];
このような配列内において、唯一String型になっているアイテムを変数itに代入することを目的とします。更に、変数it以外は同じスコープから参照不可能になるように工夫します。
var it = function(_ary){
for(var i = 0, obj, len = _ary.length; i < len; i++)
{
obj = _ary[i];
switch(obj.constructor)
{
case String :
return obj;
break;
case Array :
return arguments.callee(obj);
break;
default :
break;
}
}
}(ary);
alert(it); // it
変数itに無名関数の戻り値を代入し、その無名関数の中で自分自身(arguments.callee)を呼び出して再帰処理を行っています。
この例における配列はノードリストに、また、配列のアイテムはノードに、そしてconstructorプロパティはnodeType等判別に使用したいプロパティ等に置き換えて使用します。その際にはもう少しややこしくなりますが、考え方は同じです。