Re: [xsl] priority of key patterns

Subject: Re: [xsl] priority of key patterns
From: Ihe Onwuka <ihe.onwuka@xxxxxxxxx>
Date: Wed, 14 Nov 2012 10:00:33 +0000
On Wed, Nov 14, 2012 at 8:48 AM, Michael Kay <mike@xxxxxxxxxxxx> wrote:
>
>>
>>    <xsl:template match="key('privateData','private')" priority="-0.1">
>>      <private oldName="{local-name()}">
>>        <xsl:apply-templates select="node()|@*"/>
>>      </private>
>>    </xsl:template>
>>
>>    <xsl:template match="*|PayloadFile">
>>     <xsl:element name="{local-name()}">
>>        <xsl:apply-templates select="node()|@*"/>
>>     </xsl:element>
>>
> Your second template rule is rather peculiar, because the first alternative
> (*) embraces the second (Payloadfile); except that they have different
> priorities, so this is almost equivalent to writing a match="*" template
> with priority -0.5, and a match=Payloadfile template with priority 0. Unless
> there's another template rule with intervening priority, the second half of
> the union is pointless.
>

No it's not pointless - see explanation below.

>
> Incidentally, I very rarely see key() used in patterns. I'd be interested to
> know the use case. In XSLT 3.0 we're allowing a variable reference as a
> pattern, so you can do for example
>

Here's the full stylesheet.

<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
    xmlns="http://www.xxxxx.com";
    version="2.0">
  <xsl:import href="identity.xsl"/>
  <xsl:output indent="yes"/>
  <xsl:key name="privateData" match="*[@MetadataAccess]" use="@MetadataAccess"/>

  <xsl:template match="TMFFile">
   <xsl:element name="{local-name()}">	
    <publicData>
      <xsl:apply-templates select="key('privateData','public')"/>
    </publicData>	
    <privateData>	
      <xsl:apply-templates select="key('privateData','private')"/>
    </privateData>
   </xsl:element>
  </xsl:template>

  <xsl:template match="key('privateData','private')" priority="-0.1">
    <private oldName="{local-name()}">
      <xsl:apply-templates select="node()|@*"/>
    </private>		
  </xsl:template>

  <xsl:template match="*|PayloadFile">
   <xsl:element name="{local-name()}">	
      <xsl:apply-templates select="node()|@*"/>
   </xsl:element>
  </xsl:template>

</xsl:stylesheet>

My instance is an iteration of heterogenous elements that have a
metadataAccess attribute that classifies the element as either public
or private.

I want to rename all the private elements (except for PayloadFile) and
copy the public elements unchanged. Additionally I want to congregate
the public elements in a publicData wrapper and private elements in a
privateData wrapper.

I have used the key to get at all the private elements in preference to
<private>
  <xsl:apply-templates select="//*[@MetadataAccess='private']
</private>

but am probably not buying much by doing so.

I agree that I could use

  <xsl:template match="*[@MetadataAccess='private']" priority="-0.1">
instead of the key in the match pattern.

 <xsl:template match="*|PayloadFile"> is necessary otherwise the
previous template would snaffle PayloadFile that are private due to
its higher priority over a * pattern. So yes I am deliberately
exploiting the differing priorities of the union pattern to get the
outcome I desire which is that private PayloadFile elements should be
treated the same as public elements.


Regarding other use cases for keys in patterns - I tend to do my
renames like this

<xsl:key name="mapNames" match="ren:*/@to" use="../@from"/>
  <xsl:variable name="renames">
    <ren:element from="EmployeeCategory" to="Name"/>
    <ren:element from="PersonName" to="Name"/>
    <ren:element from="FormerlyKnown" to="Name"/>
     .
     .
   </xsl:variable>


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

Current Thread