XSLT1.0のkey関数は検索文字列を指定してノードを引っかき集める為に使います。どういった規則で何を集めるかを指定するのがxsl:key要素です。name属性にその規則の名前をQNameで指定し、match属性に返却されるノード集合の「型」をパターンで指定し、use属性に検索対象をXPath式で指定します。そのXPath式のコンテクストノードは、パターンで指定した各ノードになります。
use属性のXPath式には変数参照('$'QName)を使えないことを注意しつつ、具体的な例を見ていきましょう。
最初は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関数特有の性質を生かした例を挙げます。
今度はname属性だけではなく、あらゆる属性を検索対象にします。
<xsl:key name="getElementsByAnyAttributes" match="*" use="@*" />
key('getElementsByAnyAttributes', 'foo')
これは、"foo" という値を持つ属性をもっている要素の集合を得ます。name="foo" でも id="foo" でも、さらに、title="foo" でも、とにかく "foo" という値を持つ属性を持っていれば、その要素が、返却されるノード集合に加えられます。
先ほどの getElementsByAnyAttributesの例では、検索対象となるノードが複数ありました(@*
)。今度は、それに加えて検索文字列も複数にしてみます。
その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 検索です。
xsl:key要素を複数用意して同じ名前をつけることで、一つのkey関数でそれらの複数のルールに基づいた検索を行うことが出来ますが、例は省きます。
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)を呼び出した際: