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

Subject: [xsl] How to avoid applying templates several times to the same descendant
From: Joakim Norlov <jn@xxxxxxxxxxxxxx>
Date: Tue, 08 May 2001 12:32:55 +0900
Hi!

I have a problem with applying templates to only a selection of the
descendants of a specific node. The selection should be done depending
on the value of an attribute. This attribute can exist in all kinds of
elements, and at any level.
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."

My problem is: How can I select to "execute" only selected nodes, when I

don't know what level they are at, or what names they have. In addition
to the "spec" above, there are a bunch of other templates that also have

to apply to the elements in question.

For example:

<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>

should turn out to be

<ATLAS ATTR="Subject III">
   <PROC>
      <PAR ATTR="Subject III">
         Blabla 1
      </PAR>
      <PAR>
         Blabla 0
      </PAR>
   </PROC>
   <PROC>
   </PROC>
</ATLAS>
<ATLAS ATTR="Subject I">
   <PROC>
      <PAR>
         Blabla 0
      </PAR>
   </PROC>
   <PROC ATTR="Subject I">
      Blabla 2
   </PROC>
   <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>
   <PROC>
   </PROC>
</ATLAS>

I tried this:

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

<xsl:template match="ATLAS">
   <xsl:choose>
      <xsl:when test=".//@ATTR">
         <xsl:for-each select=".//*[@ATTR and
generate-id(.)=generate-id(key('UniqueATTR', @ATTR))]">
         <!-- to create a list of unique ATTR values -->
            <xsl:call-template name="ATLAS-LOOP">
               <xsl:with-param name="ATTR" select="@ATTR"/>
            </xsl:call-template>
         </xsl:for-each>
      </xsl:when>
      <xsl:otherwise>
         <xsl:apply-templates select="." />
      </xsl:otherwise>
   </xsl:choose>
</xsl:template>

<xsl:template name="ATLAS-LOOP">
<!-- create ATLAS duplicates, and sort out elements not belonging -->
   <xsl:param name="ATTR"/>
   <xsl:element name="ATLAS">
      <xsl:attribute name="ATTR"><xsl:value-of
select="$ATTR"/></xsl:attribute>
      <xsl:apply-templates select="ancestor::ATLAS//*[@ATTR=$ATTR or
not(@ATTR)]"/>
   </xsl:element>
</xsl:template>

<xsl:template match="*|text()|@*">
   <xsl:copy>
      <xsl:apply-templates select="*|text()|@*"/>
   </xsl:copy>
</xsl:template>

This gives me duplicates of several elements, since each descendant is
selected in ATLAS-LOOP, and all descendants of the children of ATLAS
will be selected in the "standard" apply-templates. How do I stop this
from happening?

I'm sorry for the "messy" message! I'm sure it's an easy task to solve,
but right now I'm stuck.

Thank you!

/Joakim


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


Current Thread