RE: [xsl] How to avoid applying templates several times to the same descendant

Subject: RE: [xsl] How to avoid applying templates several times to the same descendant
From: "Jarno Elovirta" <jarno@xxxxxxxxxxxxxx>
Date: Tue, 8 May 2001 10:55:58 +0300
Heippa!

> The "spec" I got sounded like this:
> "If we find any element inside ATLAS or EARTH with an attribute ATTR not
>
> null, generate as many ATLAS/EARTH elements (duplicates) as the number
> of different values of the ATTR attribute. Put this value in the ATTR
> attribute of the ATLAS/EARTH and delete all elements where ATTR does not
>
> correspond to its ATLAS/EARTH."

How about

[c:\temp]type test.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<ATLAS>
   <PROC>
      <PAR ATTR="Subject III">
         Blabla 1
      </PAR>
      <PAR>
         Blabla 0
      </PAR>
   </PROC>
   <PROC ATTR="Subject I">
      Blabla 2
   </PROC>
   <PAR ATTR="Subject II">
      Blabla 3
   </PAR>
   <PROC>
      <PAR ATTR="Subject II">
         Blabla 4
      </PAR>
   </PROC>
</ATLAS>

[c:\temp]type test.xsl
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>

<xsl:output method="xml"
            indent="yes" />

<xsl:key name="UniqueATTR" match="*[@ATTR]" use="@ATTR"/>

<xsl:template match="ATLAS">
  <xsl:for-each select=".//*[@ATTR and
generate-id(.)=generate-id(key('UniqueATTR', @ATTR))]">
    <xsl:variable name="ATTR" select="@ATTR" />
    <xsl:for-each select="/ATLAS">
      <xsl:copy>
        <xsl:copy-of select="$ATTR" />
        <xsl:apply-templates select="node()">
          <xsl:with-param name="ATTR" select="$ATTR" />
        </xsl:apply-templates>
      </xsl:copy>
    </xsl:for-each>
  </xsl:for-each>
</xsl:template>

<xsl:template match="*">
  <xsl:param name="ATTR" />
  <xsl:if test="not(@ATTR) or @ATTR = $ATTR">
    <xsl:copy>
      <xsl:copy-of select="@*" />
      <xsl:apply-templates select="node()">
        <xsl:with-param name="ATTR" select="$ATTR" />
      </xsl:apply-templates>
    </xsl:copy>
  </xsl:if>
</xsl:template>

<xsl:template match="text()">
  <xsl:value-of select="normalize-space(.)" />
</xsl:template>

</xsl:stylesheet>

[c:\temp]saxon test.xml test.xsl
<?xml version="1.0" encoding="utf-8"?>
<ATLAS ATTR="Subject III">
   <PROC>
      <PAR ATTR="Subject III">Blabla 1</PAR>
      <PAR>Blabla 0</PAR>
   </PROC>
   <PROC/>
</ATLAS>
<ATLAS ATTR="Subject I">
   <PROC>
      <PAR>Blabla 0</PAR>
   </PROC>
   <PROC ATTR="Subject I">Blabla 2</PROC>
   <PROC/>
</ATLAS>
<ATLAS ATTR="Subject II">
   <PROC>
      <PAR>Blabla 0</PAR>
   </PROC>
   <PAR ATTR="Subject II">Blabla 3</PAR>
   <PROC>
      <PAR ATTR="Subject II">Blabla 4</PAR>
   </PROC>
</ATLAS>

Which should be what you wanted, except it normalizes the whitespace in text
nodes. There are better solutions, but hope this helps,

Jarno - Assemblage 23: Love My Way


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


Current Thread