RE: [xsl] recursion with xsl:apply-templates

Subject: RE: [xsl] recursion with xsl:apply-templates
From: "Michael Kay" <mhk@xxxxxxxxx>
Date: Wed, 27 Aug 2003 12:26:34 +0100
Firstly, the line 

       <xsl:apply-templates select="descendant::*"/>

looks wrong. This processes the descendants at each level; but at each
level a node is going to process its own children, so this is
unnecessary.

Secondly, you've left something out:

     <xsl:apply-templates select>

What was the value of the select attribute?

Finally, I don't see why you need recursion at all. I think the
following should do the job:

<xsl:template match="HEADER">
 ...
 <xsl:apply-templates select="*[@index]" mode="id"/>
</xsl:template>

<xsl:template match="*" mode="id">
  <xsl:copy>
  <xsl:copy-of select="@*[not(name()='index')]"/>
  <xsl:variable name="p" select="position()"/>
  <xsl:copy-of select="/transformation/id_list/id[$p]"/>
  <xsl:copy-of select="child::node()"/>
  </xsl:copy>
</xsl:template>

But this doesn't copy the elements without an @index attribute. If
that's a requirement, and if they have to be kept in their original
order, then you can't rely on position() in this way. But all is not
lost: instead of position(), use count(preceding::*[@index])+1.

Michael Kay

> -----Original Message-----
> From: owner-xsl-list@xxxxxxxxxxxxxxxxxxxxxx 
> [mailto:owner-xsl-list@xxxxxxxxxxxxxxxxxxxxxx] On Behalf Of 
> Volker Witzel
> Sent: 27 August 2003 10:14
> To: XSL-List@xxxxxxxxxxxxxxxxxxxxxx
> Subject: [xsl] recursion with xsl:apply-templates
> 
> 
> Hi,
> 
> I have a problem with a recursion and I don't have a clue, why my 
> solution does not work. I did not find anything on the web, 
> so your help 
> is greatly appreciated.
> 
> The problem:
> I need to perform an XML to XML transformation to augment the 
> data with 
> unique keys.
> The structure is as follows:
> <transformation>
>    <IRF>
>      <HEADER>
>        <REC_IR020_01 index="1">			
>          <UNB_S002_0004>16</UNB_S002_0004>
>          ...
>        </REC_IR020_01>
>        <REC_IR030_01 index="1">
>          <UNH_0062>03081402160553</UNH_0062>
>          ...
>        </REC_IR030_01>
>       ...
>    </IRF>
>    <id_list>
>      <id>2003-08-25 15:36:59.534096</id>
>      ...
>    </id_list>
> </transformation>
> 
> I do not know all tag names, but I know that I have some 
> elements with 
> an index attribute, which I need to transform to
>        <REC_IR020_01>			
>          <id>2003-08-25 15:36:59.534096</id>
>          <UNB_S002_0004>16</UNB_S002_0004>
>          ...
>        </REC_IR020_01>
> So I have to strip the index attribute and fetch one unique 
> id from the 
> id_list for each occurence of an index attribute.
> 
> My Solution:
> I thought it's startightforward with XSL. My code:
> 
> <?xml version="1.0" encoding="UTF-8"?>
> <xsl:stylesheet version="1.0" 
> xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; 
> xmlns:xalan="http://xml.apache.org/xslt";>
>    <xsl:output method="xml" indent="yes" encoding="UTF-8" 
> omit-xml-declaration="no" xalan:indent-amount="2" />
>    <xsl:strip-space elements="*"/>
>    <xsl:template match="/transformation">
>      <xsl:apply-templates select="IRF"/>
>    </xsl:template>
>    <xsl:template match="IRF">
>      <xsl:copy>
>        <xsl:copy-of select="@*"/>
>        <xsl:apply-templates select="descendant::*"/>
>      </xsl:copy>
>    </xsl:template>
>    <xsl:template match="node()">
>      <xsl:param name="idCount" select="1"/>
>      <xsl:choose>
>        <xsl:when test="@index">
>          <xsl:copy>
>            <xsl:element name="test"><xsl:value-of 
> select="$idCount"/></xsl:element>
>            <xsl:call-template name="addIdElement">
>              <xsl:with-param name="idCount" select="$idCount"/>
>            </xsl:call-template>
>            <xsl:apply-templates select>
>              <xsl:with-param name="idCount" select="$idCount + 1"/>
>            </xsl:apply-templates>
>          </xsl:copy>
>        </xsl:when>
>        <xsl:otherwise>
>          <xsl:copy>
>            <xsl:apply-templates>
>              <xsl:with-param name="idCount" select="$idCount"/>
>            </xsl:apply-templates>
>          </xsl:copy>
>        </xsl:otherwise>
>      </xsl:choose>
>    </xsl:template>
>    <xsl:template name="addIdElement">
>      <xsl:param name="idCount"/>
>      <xsl:element name="id">
>      <xsl:copy-of select="/transformation/id_list/id[$idCount]"/>
>    </xsl:template>
> </xsl:stylesheet>
> 
> My problem is that the lines
>            <xsl:apply-templates select>
>              <xsl:with-param name="idCount" select="$idCount + 1"/>
>            </xsl:apply-templates>
> do not call the template with the inceremnted parameter, so it always 
> runs with the default value 1.
> 
> Any ideas where my brain is scrumbled?
> Volker.
> 
> 
> 
>  XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
> 


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


Current Thread