Stylus Studio XML Editor

Table of contents

Appendices

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:

  1. the node which has the key

  2. the name of the key (an expanded-name)

  3. 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>