Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   XML (http://www.velocityreviews.com/forums/f32-xml.html)
-   -   XSLT: Perform an action once per element type? (http://www.velocityreviews.com/forums/t165451-xslt-perform-an-action-once-per-element-type.html)

Stuart A Yeates 08-20-2003 12:33 PM

XSLT: Perform an action once per element type?
 
I'm trying to write a template that matches "*" but which has an if
clause which if only executed once per type of element seen (where
all elements of a type have the same name and namespace). The test
in the example below doesn't work, but it seems that there must be
some relatively simple text i'm overlooking.

<!--
- process an element
-->
<xsl:template match="*">
<xsl:copy>
<xsl:if test="last()=position()">
<xsl:text>
i occur once for each type of element. this time it's for:
</xsl:text>
<xsl:value-of select="."/>
</xsl:if>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>

If my input is:

<a>
<b> <d/><d/> </b>
<c> <d/><b/> </c>
</a>

I want instantiate the body of my if once for <a>, once for <b>,
once for <c> and once for <e>. It doesn't really bother me what
order they happen it.

I suspect that what I need is a recursive template that finds
determines whether the current element occupies some special
place (first or last), but i'm not sure how to write it.

stuart
--
-- stuart yeates <s.yeates@cs.waikato.ac.nz> aka `loam'
Sufficiently advanced political correctness is indistinguishable
from irony.
X-no-archive:yes

Dimitre Novatchev 08-20-2003 01:19 PM

Re: Perform an action once per element type?
 
Use:

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes"/>

<xsl:key name="kName" match="*" use="name()"/>

<xsl:template match="*[generate-id()
= generate-id(key('kName',
name()
)[1]
)
]">
Element name: <xsl:value-of select="name()"/>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="node()[not(self::*)]"/>
</xsl:stylesheet>

This transformation, when applied on your source.xml:

<a>
<b>
<d/>
<d/>
</b>
<c>
<d/>
<b/>
</c>
</a>

produces the desired result:


Element name: a
Element name: b
Element name: d
Element name: c


Read about the "Muenchian method for grouping" in order to understand what
actually happens here.



=====
Cheers,

Dimitre Novatchev.
http://fxsl.sourceforge.net/ -- the home of FXSL

"Stuart A Yeates" <say1@bedrock.cs.waikato.ac.nz> wrote in message
news:1061382788.597583@clint.its.waikato.ac.nz...
> I'm trying to write a template that matches "*" but which has an if
> clause which if only executed once per type of element seen (where
> all elements of a type have the same name and namespace). The test
> in the example below doesn't work, but it seems that there must be
> some relatively simple text i'm overlooking.
>
> <!--
> - process an element
> -->
> <xsl:template match="*">
> <xsl:copy>
> <xsl:if test="last()=position()">
> <xsl:text>
> i occur once for each type of element. this time it's for:
> </xsl:text>
> <xsl:value-of select="."/>
> </xsl:if>
> <xsl:apply-templates/>
> </xsl:copy>
> </xsl:template>
>
> If my input is:
>
> <a>
> <b> <d/><d/> </b>
> <c> <d/><b/> </c>
> </a>
>
> I want instantiate the body of my if once for <a>, once for <b>,
> once for <c> and once for <e>. It doesn't really bother me what
> order they happen it.
>
> I suspect that what I need is a recursive template that finds
> determines whether the current element occupies some special
> place (first or last), but i'm not sure how to write it.
>
> stuart
> --
> -- stuart yeates <s.yeates@cs.waikato.ac.nz> aka `loam'
> Sufficiently advanced political correctness is indistinguishable
> from irony.
> X-no-archive:yes





All times are GMT. The time now is 10:21 AM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.