[XSL-LIST Mailing List Archive Home] [By Thread] [By Date]

Re: [xsl] key() now has 3 arguments ... right

Subject: Re: [xsl] key() now has 3 arguments ... right
From: Michael Kay <mike@xxxxxxxxxxxx>
Date: Wed, 25 Apr 2012 09:22:51 +0100

In this example your call to key() is in a predicate. In a predicate you can use any XPath expression, with very few exceptions (for example, you can't call current-group()).

In your previous example, the one that failed, the call to key() was outside a predicate. That's subject to the restrictions applicable to XSLT patterns, one of which is that the call must only have two arguments. (Another is that the key name must be a literal.)

Michael Kay Saxonica

On 25/04/2012 03:06, ihe onwuka wrote:
The reason I didn't comment on David's answer was because I was confused by it.
Now I know why I was confused.

The code from which the snippet I posted was derived  is a tabular
driven utility to rename elements and attributes. No doubt it could be
done another way. The point is it uses a 3 argument key in template
matching patterns and

a) it shows why I wanted to use the 3 argument version
b) it works.

<?xml version="1.0" encoding="UTF-8"?>

<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="mapNames" match="ren:*/@to" use="../@from"/>

<xsl:variable name="renames">
    <ren:element from="person" to="individual"/>
    <ren:attribute from="firstname" to="christianname"/>
    <ren:attribute from="lastname" to="surname"/>

<xsl:template match="*[key('mapNames',name(),$renames)]">
     <xsl:element name="{key('mapNames',name(),$renames)}">

<xsl:template match="*[not(key('mapNames',name(),$renames))] | @*">
     <xsl:element name="{name()}">

<xsl:template match="*">
      <xsl:apply-templates select="@*"/>

<xsl:template match="@*[key('mapNames',name(),$renames)]">
     <xsl:attribute name="{key('mapNames',name(),$renames)}">


Try it with

     <person firstname="Sal" lastname="Mangano" age="38" height="5.75"/>
     <person firstname="Mike" lastname="Palmieri" age="28" height="5.10"/>
     <person firstname="Vito" lastname="Palmieri" age="38" height="6.0"/>
     <person firstname="Vinny" lastname="Mari" age="37" height="5.8"/>

When people ask for reasons why the spec is as it is, there are two ways of
(b) the post-hoc justification: "can you defend the fact that the spec is
the way it is?". Here I think my answer would be that the syntax for
patterns is a very restricted subset of the syntax of XPath expressions, and
the WG has been traditionally conservative about extending it, probably in
the belief that a smaller language is much more susceptible to the kind of
analysis needed to build an efficient decision tree. There has also been
historically little demand for a more powerful pattern language, with most
users keeping patterns very simple most of the time.

key() in patterns is used very little, and serves very little purpose, since
unlike key() in XPath expressions an index does not help evaluation and
there is really no strong reason to use key() in preference to using a
predicate. Adding the third argument to key() would be oddly asymmetric:
since there is no way in XSLT 2.0 of rooting a pattern such as $x/a/b/c at a
specific document node, it would be odd to allow a key() pattern to be
rooted in that way.

Michael Kay

Current Thread