key


The key() function is used to find the nodes with a given value for a named key. It is used in conjunction with the <xsl:key> element described on page 332 in Chapter 5.

For example, if there is a key definition:

 <xsl:key name="vreg" match="vehicle" use="@reg"/> 

then the expression «key ('vreg', 'N498PAA') » might return the single element <vehicle reg="N498PAA"> .

Changes in 2.0

The key value can now be of any data type, and is compared according to the rules for that data type. The key definitions in <xsl:key> can also now specify a collation to be used for comparing strings.

An optional third argument has been added to identify the document to be searched.

Signature

Argument

Data Type

Meaning

name

xs:string

Specifies the name of the key. The value of the string must be a lexical QName that identifies a key declared using an <xsl:key> element in the stylesheet.

value

xdt:anyAtomicType*

Specifies the required value of the key, in a way that depends on the data type. See below.

document (optional)

node()

Identifies the document to be searched. If this argument is omitted, the document containing the context node is searched.

Result

node() *

The nodes with the required key values, returned without duplicates, and in document order.

Effect

The first argument must take the form of a lexical QName: that is, an XML name optionally prefixed with a namespace prefix that corresponds to a namespace declaration that is in scope at the point in the stylesheet where the key() function is called. If there is no namespace prefix, the relevant namespace URI is null; the default namespace is not used. There must be an <xsl:key> element in the stylesheet with the same expanded QName, using the namespace URIs rather than prefixes in the comparison. If there is more than one <xsl:key> element with this name, they are all used: a node is considered to match the key if it matches any of the key definitions with this name.

The second argument is a sequence of atomic values (usually a single atomic value, but this is treated as a sequence of length one). If the value actually supplied in the function call includes nodes, the nodes are atomized to create a sequence of atomic values. The result of the key() function contains every node in the same document as the context node that has at least one key value that is equal to one of the values supplied in this sequence.

The key values can be of any data type. The values of the keys as indexed using <xsl:key> will be compared with the keys supplied in the key() function, using the rules of the XPath «eq » operator without any special type conversion: this means for example that if the indexed value is the xs:integer value 23, it will not be retrieved by the call «key('k', '23') » , because the integer 23 and the string '23' do not compare equal. Untyped atomic values (values extracted from unvalidated nodes) are treated as strings and can only be compared with strings. If a collation is specified in the <xsl:key> declaration, it will be used when comparing strings, otherwise the default collation will be used.

The optional third argument identifies the document to be searched. This can be any node in the relevant document; it does not need to be the document node. The default value is the context node. Note that with multiple source documents, the resulting nodes will all be in this document, which is not necessarily the same document as the nodes from which the key values were obtained.

When the third argument is omitted, it's an error if there is no context item, or if the context item isn't a node. It's also an error to search in a tree that doesn't have a document node as its root.

Usage and Examples

The key() function is provided to make associative access to nodes (finding the nodes given their content) more convenient and more efficient. Efficiency of course depends entirely on the implementation, but it is likely that most implementations will use some kind of index or hash-table data structure to make the key() function faster than the equivalent path expression using predicates to select the required value.

Another use for keys is that they provide an efficient way of grouping related nodes together. This usage is needed far less under XSLT 2.0, because of the introduction of the <xsl:for-each- group > instruction, but it is still worth your while to understand it.

We will examine these two ways of using keys in turn .

Using Keys to Find Nodes by Value

To locate the <book> elements having J. B. Priestley as the content of one of their <author> child elements, you could write:

  <xsl:for-each select="//book[author='J. B. Priestley']">  

However, it is probably more efficient, if this is done frequently in the stylesheet, to define the author name as a key.

  <xsl:key name="book-author" match="book" use="author"/>   . . .   <xsl:for-each select="key('book-author', 'J. B. Priestley')"/>  

The key() function normally locates elements in the same document as the context node. When you need to locate elements in a different document, you can identify this in the third argument, for example:

  <xsl:copy-of select="key('book-author', 'J. B. Priestley', document('a.xml'))"/>  

The key value is usually supplied as a string, or as an expression that returns a string. In XSLT 2.0 it can also be a value of another atomic type: for example, you can use a number or a date as a key. It does not have to be a single value; you can supply a sequence of strings (or numbers or dates, if that is how the key is defined), and the function will return all the nodes that match any one of the values.

Keys are particularly useful for following cross-references. If you supply the key value as a node, or a sequence of nodes, then the values held in those nodes will be used as the key values. The next example explores this in more detail.

Using Keys as Cross-References
start example

This example uses two source files: the principal source document is a file containing a list of books, and the secondary one (accessed using the document() function) contains biographies of authors. The author name held in the first file acts as a cross-reference to the author's biography in the second file, rather like a join in SQL.

Source

The principal source document is an abbreviated version of the booklist.xml file.

  <booklist>   <book category="FC">   <title>The Young Visiters</title>   <author>Daisy Ashford</author>   </book>   <book category="FC">   <title>When We Were Very Young</title>   <author>A. A. Milne</author>   </book>   </booklist>  

The secondary source document, authors.xml , reads like this. I've included only two authors to keep it short, but the key() function would really come into its own if there were hundreds of entries.

  <authors>   <author name="A. A. Milne">   <born>1852</born>   <died>1956</died>   <biog>Alan Alexander Milne, educated at Westminster School and Trinity   College Cambridge, became a prolific author of plays, novels, poetry,   short stories, and essays, all of which have been overshadowed by his   children's books. </biog>   </author>   <author name="Daisy Ashford">   <born>1881</born>   <died>1972</died>   <biog>Daisy Ashford (Mrs George Norman) wrote <i>The Young Visiters</i>,   a small comic masterpiece, while still a young child in Lewes. It was   found in a drawer in 1919 and sent to Chatto and Windus, who published   it in the same year with an introduction by J. M. Barrie, who had first   insisted on meeting the author in order to check that she was genuine.   </biog>   </author>   </authors>  

Stylesheet

The stylesheet is in the file author-biogs.xsl . It declares a key to match <author> elements by their name attribute. This is intended for use with the authors.xml file, though there is nothing in the key definition to say so.

Note the use of a global variable to reference the secondary source file. It would be possible to use the document() function each time the file is accessed, and any XSLT processor worthy of the name would actually read and parse the file only once, but using a variable in my view makes it easier to see what is going on.

The actual call on the key() function is in the path expression «$biogs /key ('biog', $name) » . The purpose of the first step, $biogs , is to switch the context node to the authors.xml document, because the key() function (when used with two arguments) always looks in the document containing the context node. The expression could equally have been written «key ('biog', $name, $biogs) » .

  <xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform"   version="2.0"   >   <xsl:key name="biog" match="author" use="@name"/>   <xsl:variable name="biogs" select="document('authors.xml')"/>   <xsl:template match="/">   <html><body>   <xsl:variable name="all-books" select="//book"/>   <xsl:for-each select="$all-books">   <!-- for each book in the booklist file -->   <h1><xsl:value-of select="title"/></h1>   <h2>Author<xsl:if test="count(author)!=1">s</xsl.if></h2>   <xsl:for-each select="author">   <!-- for each author of this book -->   <xsl:variable name="name" select="."/>   <h3><xsl:value-of select="$name"/></h3>   <!--locate the biography by key lookup -->   <xsl:variable name="auth"   select="$biogs/key('biog', $name)"/>   <p><xsl:value-of   select="concat($auth/born, ' - ', $auth/died)"/>   </p>   <p><xsl:value-of select="$auth/biog"/></p>   </xsl:for-each>   </xsl:for-each>   </body></html>   </xsl:template>   </xsl:transform>  

Output

The output obtained if you run this stylesheet with the subset of the booklist.xml file shown earlier is as follows .

  <html>   <body>   <h1>The Young Visiters</h1>   <h2>Author</h2>   <h3>Daisy Ashford</h3>   <p>1881 - 1972</p>   <p>Daisy Ashford (Mrs George Norman) wrote The Young Visiters, a   small comic masterpiece, while still a young child in Lewes. It was   found in a drawer in 1919 and sent to Chatto and Windus, who published   it in the same year with an introduction by J.M.Barrie, who had first   insisted on meeting the author in order to check that she was genuine.   </p>   <;h1>When We Were Very Young</h1>   <h2>Author</h2>   <h3>A. A. Milne</h3>   <p>1852 - 1956</p>   <p>Alan Alexander Milne, educated at Westminster School and   Trinity College Cambridge, became a prolific author of plays, novels,   poetry, short stories, and essays, all of which have been overshadowed   by his children's books.</p>   </body>   </html>  
end example
 

Using Keys for Grouping

Because keys provide an efficient way of retrieving all the nodes that share a common value, they are useful when you need to group nodes with common values in the output.

This technique is sometimes called the Muenchian grouping method, after Steve Muench of Oracle who introduced it. In XSLT 1.0, it was the only way of performing grouping efficiently . In XSLT 2.0, the <xsl:for-each-group> construct will usually provide a more convenient solution; however, you will still encounter the Muenchian method used in old stylesheets, and there is no reason why you should not continue to use it.

To solve any grouping problem, you need two nested loops . The outer loop selects one node to act as a representative of each group, typically the first node in document order that is a member of the group. The processing associated with this node outputs information about the group as a whole, typically the common value used to group the nodes together, perhaps with counts or subtotals calculated over the members of the group, plus any necessary formatting. The inner loop then processes each member of the group in turn.

With the Muenchian method, a key is defined on the common value that determines group membership. For example, if all the cities in a country comprise one group, then the key definition will be as follows.

  <xsl:key name="country-group" match="city" use="@country"/>  

The outer loop selects one city for each country. The way of doing this is to select all the cities, and then filter out those that are not the first in their country. You can tell that a city is the first one for its country, by comparing it with the first node in the sequence returned by the key() function for that country.

  <xsl:for-each select="//city[. is key('country-group', @country)[1]]">  

The «is » operator is new in XPath 2.0. In a 1.0 stylesheet, the equivalent expression would apply generate-id () to both operands, and compare the results using the «= » operator.

Within this loop the code can output any heading it needs, such as the name of the country. It can then start an inner loop to process all the cities in this country, which it can find by using the key once again.

  <xsl:for-each select="key('country-group', @country)">  

The following shows a complete example of this technique.

Using Keys for Grouping
start example

This example creates a list of cities, grouped by country.

Source

The source cities.xml is a list of cities.

  <cities>   <city name="Paris" country="France"/>   <city name="Roma" country="Italia"/>   <city name="Nice" country="France"/>   <city name="Madrid" country="Espana"/>   <city name="Milano" country="Italia"/>   <city name="Firenze" country="Italia"/>   <city name="Napoli" country="Italia"/>   <city name="Lyon" country="France"/>   <city name="Barcelona" country="Espana"/>   </cities>  

Stylesheet

The stylesheet citygroups.xsl is as follows.

  <xsl:transform   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"   version="2.0"   >   <xsl:key name="country-group" match="city" use="@country"/>   <xsl:template match="/">   <html><body>   <xsl:for-each   select="//city[. is key('country-group', @country) [1]]">   <h1><xsl:value-of select="@country"/></h1>   <xsl:for-each select="key('country-group', @country)">   <xsl:value-of select="@name" /><br/>   </xsl:for-each>   </xsl:for-each>   </body></html>   </xsl :template>   </xsl:transform>  

Output

Viewed in a browser, the output is as shown in Figure 7-2.

click to expand
Figure 7-2
end example
 

See Also

  • <xsl:key> on page 332 in Chapter 5.

  • id() in XPath 2.0 Programmer's Reference (Chapter 10).




XSLT 2.0 Programmer's Reference
NetBeansв„ў IDE Field Guide: Developing Desktop, Web, Enterprise, and Mobile Applications (2nd Edition)
ISBN: 764569090
EAN: 2147483647
Year: 2003
Pages: 324

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net