This is the mail archive of the
xsl-list@mulberrytech.com
mailing list .
How to avoid applying templates several times to the same descendant
- To: XSL Mailing list <XSL-List at lists dot mulberrytech dot com>
- Subject: [xsl] How to avoid applying templates several times to the same descendant
- From: Joakim Norlov <jn at uniscope dot co dot jp>
- Date: Tue, 08 May 2001 12:32:55 +0900
- Reply-To: xsl-list at lists dot mulberrytech dot com
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