12.2 Keys
Keys
Keys provide a way to work with documents that contain an implicit
cross-reference structure. The ID, IDREF
and IDREFS attribute types in XML provide a mechanism to
allow XML documents to make their cross-reference explicit. XSLT
supports this through the XPath id function.
However, this mechanism has a number of limitations:
-
ID attributes must be declared as such in the DTD. If an ID
attribute is declared as an ID attribute only in the external DTD
subset, then it will be recognized as an ID attribute only if the XML
processor reads the external DTD subset. However, XML does not require
XML processors to read the external DTD, and they may well choose not
to do so, especially if the document is declared
standalone="yes".
-
A document can contain only a single set of unique IDs.
There cannot be separate independent sets of unique IDs.
-
The ID of an element can only be specified in an attribute;
it cannot be specified by the content of the element, or by a child
element.
-
An ID is constrained to be an XML name. For example, it
cannot contain spaces.
-
An element can have at most one ID.
-
At most one element can have a particular ID.
Because of these limitations XML documents sometimes contain a
cross-reference structure that is not explicitly declared by
ID/IDREF/IDREFS attributes.
A key is a triple containing:
-
the node which has the key
-
the name of the key (an expanded-name)
-
the value of the key (a string)
A stylesheet declares a set of keys for each document using the
xsl:key element. When this set of keys contains a member
with node x, name y and value
z, we say that node x has a key with name
y and value z.
Thus, a key is a kind of generalized ID, which is not subject to the
same limitations as an XML ID:
-
Keys are declared in the stylesheet using
xsl:key elements.
-
A key has a name as well as a value; each key name may be
thought of as distinguishing a separate, independent space of
identifiers.
-
The value of a named key for an element may be specified in
any convenient place; for example, in an attribute, in a child element
or in content. An XPath expression is used to specify where to find
the value for a particular named key.
-
The value of a key can be an arbitrary string; it is not
constrained to be a name.
-
There can be multiple keys in a document with the same node,
same key name, but different key values.
-
There can be multiple keys in a document with the same key
name, same key value, but different nodes.
<
key
name=
qname
match=
pattern
use=
expression
>
<-- Content: -->
<
/key>
The xsl:key element is used to declare keys. The
name attribute specifies the name of the key. The value
of the name attribute is a QName, which is expanded as described
in [Qualified Names]. The match attribute is a Pattern; an xsl:key element gives
information about the keys of any node that matches the pattern
specified in the match attribute. The use attribute is
an Expression specifying the
values of the key; the expression is evaluated once for each node that
matches the pattern. If the result is a node-set, then for each node
in the node-set, the node that matches the pattern has a key of the
specified name whose value is the string-value of the node in the
node-set; otherwise, the result is converted to a string, and the node
that matches the pattern has a key of the specified name with value
equal to that string. Thus, a node x has a key with name
y and value z if and only if there is an
xsl:key element such that:
-
x matches the pattern specified in the
match attribute of the xsl:key element;
-
the value of the name attribute of the
xsl:key element is equal to y;
and
-
when the expression specified in the use
attribute of the xsl:key element is evaluated with
x as the current node and with a node list containing
just x as the current node list resulting in an object
u, then either z is equal to the result of
converting u to a string as if by a call to the
string function, or u is a
node-set and z is equal to the string-value of one or
more of the nodes in u.
Note also that there may be more than one xsl:key
element that matches a given node; all of the matching
xsl:key elements are used, even if they do not have the
same Import Precedence.
It is an error for the value of either the use
attribute or the match attribute to contain a VariableReference.
node-set key(string, object)
The key function does for keys what the
id function does for IDs. The first argument
specifies the name of the key. The value of the argument must be a
QName, which is expanded as
described in [Qualified Names]. When the second argument to the
key function is of type node-set, then the result
is the union of the result of applying the key
function to the string value of each of the nodes in the
argument node-set. When the second argument to
key is of any other type, the argument is
converted to a string as if by a call to the
string function; it returns a node-set
containing the nodes in the same document as the context node that
have a value for the named key equal to this string.
For example, given a declaration
<xsl:key name="idkey" match="div" use="@id"/>
an expression key("idkey",@ref) will return the same
node-set as id(@ref), assuming that the only ID attribute
declared in the XML source document is:
<!ATTLIST div id ID #IMPLIED>
and that the ref attribute of the current node
contains no whitespace.
Suppose a document describing a function library uses a
prototype element to define functions
<prototype name="key" return-type="node-set">
<arg type="string"/>
<arg type="object"/>
</prototype>
and a function element to refer to function names
<function>key</function>
Then the stylesheet could generate hyperlinks between the
references and definitions as follows:
<xsl:key name="func" match="prototype" use="@name"/>
<xsl:template match="function">
<b>
<a href="#{generate-id(key('func',.))}">
<xsl:apply-templates/>
</a>
</b>
</xsl:template>
<xsl:template match="prototype">
<p><a name="{generate-id()}">
<b>Function: </b>
...
</a></p>
</xsl:template>
The key can be used to retrieve a key from a
document other than the document containing the context node. For
example, suppose a document contains bibliographic references in the
form <bibref>XSLT</bibref>, and there is a
separate XML document bib.xml containing a bibliographic
database with entries in the form:
<entry name="XSLT">...</entry>
Then the stylesheet could use the following to transform the
bibref elements:
<xsl:key name="bib" match="entry" use="@name"/>
<xsl:template match="bibref">
<xsl:variable name="name" select="."/>
<xsl:for-each select="document('bib.xml')">
<xsl:apply-templates select="key('bib',$name)"/>
</xsl:for-each>
</xsl:template>
|