Jintrick.netagenda2003年10月アーカイブ → 2003年10月04日

key関数の考察(XSLT1.0)

XSLT1.0のkey関数は検索文字列を指定してノードを引っかき集める為に使います。どういった規則で何を集めるかを指定するのがxsl:key要素です。name属性にその規則の名前をQNameで指定し、match属性に返却されるノード集合の「型」をパターンで指定し、use属性に検索対象をXPath式で指定します。そのXPath式のコンテクストノードは、パターンで指定した各ノードになります。

use属性のXPath式には変数参照('$'QName)を使えないことを注意しつつ、具体的な例を見ていきましょう。

例:getElementsByName

最初はDOMのメソッドとして考えると分かり易いかも知れません。試しに、getElementsByName関数を作ってみます。

<xsl:key name="getElementsByName" match="*" use="@name" />

match属性に戻り値の型を指定すると考えると分かりやすいと思います。得たいのは要素名を問わない要素ノードの集合ですから、*を指定します。

use属性に検索対象を指定します。見たいのはname属性ですから、@nameを指定します。コンテクストノードはmatch属性に指定したパターンにマッチした各ノードになります。

これは次のようにして呼び出します。

key("getElementsByName", 'foo')

これで、"foo" という値を持つname属性を持った要素の集合が得られます。

これでは宝の持ち腐れ

しかし、そのような単純な用途に使うなら、descendant::*[string(@name) = 'foo'] とすれば良いだけの話であり、key関数を使うまでもありません。もう少しkey関数特有の性質を生かした例を挙げます。

例:getElementsByAnyAttributes その1

今度はname属性だけではなく、あらゆる属性を検索対象にします。

<xsl:key name="getElementsByAnyAttributes" match="*" use="@*" />
key('getElementsByAnyAttributes', 'foo')

これは、"foo" という値を持つ属性をもっている要素の集合を得ます。name="foo" でも id="foo" でも、さらに、title="foo" でも、とにかく "foo" という値を持つ属性を持っていれば、その要素が、返却されるノード集合に加えられます。

or 検索?

先ほどの getElementsByAnyAttributesの例では、検索対象となるノードが複数ありました(@*)。今度は、それに加えて検索文字列も複数にしてみます。

例:getElementsByAnyAttributes その2 (or 検索)

その1と同じく、検索ルールは次のように定めます。

<xsl:key name="getElementsByAnyAttributes" match="*" use="@*" />

次のようなXMLツリーがあるとします。

<query>
  <item>foo</item>
  <item>bar</item>
</query>

カレントノード(コンテクストノード)がこのquery要素であるとすれば:

key('getElementsByAnyAttributes', self::query/item)
<!-- self軸はコンテクストノードを明示するために使用しているだけ -->

このkey関数は、"foo" または "bar" という値の任意の属性を持った要素全てを含むノード集合を返却します。or 検索です。

さらに強力なkey関数

xsl:key要素を複数用意して同じ名前をつけることで、一つのkey関数でそれらの複数のルールに基づいた検索を行うことが出来ますが、例は省きます。

XPath 1.0 の一貫性の無いデータモデル

XPath1.0 では、集合の概念を持っているのがノードだけで、文字列や数値は明示的にリスト化することができません。これがkey関数その他を解りにくくしている要因です。2.0では改善されると思います。

例えば、多くの言語のように['foo', 'bar']という記法で文字列の配列を表現できたなら、 先の例はkey('getElementsByAnyAttributes', ['foo', 'bar'])と書けた筈です。

これが出来ないため、複数の「キーワード」で or 検索を行う際にはノードの文字列値を「検索文字」にせざるを得ません。かなり不自由な「検索」であると言えるでしょう。キーワードが一つであれば、例えばノードのローカル名を使ったり出来ます。

key( 'getElementsByAnyAttribute', local-name() )

一般論

これまでDOMのメソッドのようにxsl:key要素及びkey関数を考えたり、検索のメタファを使ったりしました。やや形式的になりますが、こうした比喩を離れてみます。

<xsl:key name="somekey" match="Pattern" use="expression" />を考えます。

あるkey関数 key('someKey', object)を呼び出した際:

  1. "someKey" という名前を持つxsl:key要素の、Pattern(match属性)にマッチする全てのノードがコンテクストノードリスト P になる
  2. 空のノード集合 C が形成される
  3. use属性のXPath式 expression が、各コンテクストノード p について評価される
  4. その他の "someKey" という名前を持つxsl:key要素があれば、同様のプロセスを経て、ノード集合 C' が形成される。
  5. C と C' の和集合が返却される

webmaster@jintrick.net
公開: 2003年10月04日
カテゴリ: XPath ,XSLT