xsl-list
[Top] [All Lists]

RE: xsl:key on variable containing result of apply-templates

2002-11-25 02:20:25
Hello,
This is my first post to this list and I apologize for it's 
length.  My 
question basically is whether it is possible to create a key 
on a variable 
which contains the result of applying a template?

This is my umpteenth answer on this list and I apologize for its
brevity.

The answer is yes. When you declare a key using xsl:key then you can use
the key() function referencing that key with ANY source document
including a temporary tree. If necessary, use xsl:for-each to ensure
that the correct document is current before calling key().

Michael Kay
Software AG
home: Michael(_dot_)H(_dot_)Kay(_at_)ntlworld(_dot_)com
work: Michael(_dot_)Kay(_at_)softwareag(_dot_)com 


  In my real 
stylesheet 
and xml the template which creates the node-set I would like 
to create the 
key on is much more complicated than the example I have given 
below - but 
the concept is the same.  I apply-templates to the source 
document and the 
result tree fragment is kept in a variable ($alphabet). I 
convert this to a 
node-set ($alphabet-exslNodeSet) and then use that node-set 
in another 
template.  It works but is pretty slow - I think it would be 
much faster if 
I were able to create a key on the node-set (each item in the 
node set is 
used multiple times).  I can't see how to do that - it looks like my 
attempt below gives me the code in the variable, not the 
result.  I know I 
can't use a variable in the key's match attribute, so I'm at 
a loss how to 
do this.
Thanks for any suggestions,
Grainne.

The Stylesheet:
============
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" 
xmlns:saxon="http://icl.com/saxon"; 
xmlns:exsl="http://exslt.org/common";
exclude-result-prefixes="ss"
extension-element-prefixes="exsl saxon">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

      <xsl:variable name="alphabet">
              <xsl:apply-templates 
select="/test/alphabetList/alphabet" mode="loadList"/>
      </xsl:variable>

      <xsl:variable 
name="alphabet-NodeSet" 
select="document('')/xsl:stylesheet/xsl:variable[(_at_)name='alphabet']" />
      <xsl:variable name="alphabet-exslNodeSet" 
select="exsl:node-set($alphabet)"/>
      
      <xsl:key name="myKey" 
match="/*/xsl:variable[(_at_)name='alphabet']" use="@col"/>

      <xsl:template match="alphabet" mode="loadList">
              <xsl:copy-of select="."/>
      </xsl:template>

      <xsl:template match="*"/>
              
      <xsl:template match="/">
              Value of alphabet variable is:<xsl:text>
              </xsl:text> <xsl:copy-of select="$alphabet"/><xsl:text>
              </xsl:text>
              Value of alphabet-NodeSet varaible is (I think 
this is what I get in the 
key!!)<xsl:text>
              </xsl:text><xsl:copy-of 
select="$alphabet-NodeSet"/><xsl:text>
              </xsl:text>
              Value of alphabet-exslNodeSet variable is <xsl:text>
              </xsl:text><xsl:copy-of 
select="$alphabet-exslNodeSet"/>      <xsl:text>
              </xsl:text>
              <xsl:apply-templates select="test/numbers"/>    
      </xsl:template>
      
              
      <xsl:template match="numbers">
              <xsl:for-each select="number">
                      <xsl:variable name="curPosition" 
select="position()"/>
                      Using the key to get the alphabet 
element (THIS is what I'd like to do 
since each node in the set is used multiple times):
                      <number value="{.}">
                      <xsl:for-each select="document('')">
                              <xsl:copy-of 
select="key('myKey',$curPosition)"/>
                      </xsl:for-each>
                      </number>
                      Using the exslNodeSet variable to get 
the alphabet element (what I am 
doing but which is very slow in my real code):
                      <number value="{.}">
                      <xsl:copy-of 
select="$alphabet-exslNodeSet/alphabet[(_at_)col=$curPosition]"/>
                      </number>
                      <xsl:text>
                      </xsl:text>                     
              </xsl:for-each> 
      </xsl:template> 
      
</xsl:stylesheet>



Example xml:
==========
<?xml version="1.0" encoding="UTF-8"?>
<test>
      <alphabetList>
              <alphabet col="1">a</alphabet>
              <alphabet col="2">b</alphabet>
              <alphabet col="3">c</alphabet>
              <alphabet col="4">d</alphabet>
              <alphabet col="5">e</alphabet>
      </alphabetList>
      <numbers>
              <number>one</number>
              <number>two</number>
              <number>three</number>
              <number>four</number>
              <number>five</number>
      </numbers>
</test>

Result (tidied up a little):
====================
<?xml version="1.0" encoding="UTF-8"?>
Value of alphabet variable is:
<alphabet col="1">a</alphabet>
<alphabet col="2">b</alphabet>
<alphabet col="3">c</alphabet>
<alphabet col="4">d</alphabet>
<alphabet col="5">e</alphabet>
              
Value of alphabet-NodeSet varaible is (I think this is what I 
get in the key!!) <xsl:variable 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; 
xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" 
xmlns:saxon="http://icl.com/saxon"; 
xmlns:exsl="http://exslt.org/common"; 
name="alphabet">              
    <xsl:apply-templates select="/test/alphabetList/alphabet" 
mode="loadList"/> </xsl:variable>
              
Value of alphabet-exslNodeSet variable is
<alphabet col="1">a</alphabet>
<alphabet col="2">b</alphabet>
<alphabet col="3">c</alphabet>
<alphabet col="4">d</alphabet>
<alphabet col="5">e</alphabet>
              
                      Using the key to get the alphabet 
element (THIS is what I'd like to do 
since each node in the set is used multiple times):
                      <number value="one"/>
                      Using the exslNodeSet variable to get 
the alphabet element (what I am 
doing but which is very slow in my real code):
                      <number value="one">
                      <alphabet col="1">a</alphabet>
                      </number>
                      
...<snip>...                  
                      Using the key to get the alphabet 
element (THIS is what I'd like to do 
since each node in the set is used multiple times):
                      <number value="five"/>
                      Using the exslNodeSet variable to get 
the alphabet element (what I am 
doing but which is very slow in my real code):
                      <number value="five">
                      <alphabet col="5">e</alphabet>
                      </number>
                      



 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list



 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list