Just as I was about to hit send Mukul and Andreas already took care of
business. Good morning guys!
Not to take away from Mukul and Andreas excellent solutions but instead
to show a slight variation which, when the situation is appropriate
(using variables are great because you can utilize the results for
grouping purposes throughout the lifecycle of the stylesheet. Mukul's
for-each method will give you similar results to this apply-templates
method. I find that a combination of both the variable and the for-each
or apply-templates methods is a perfect combination if you want
flexibility to do things like change the name of an element or attribute
of each group member and then access the results using a variable
reference later in your stylesheets(you will need to become familiar
with your processors nodeset function first). For example this XSLT:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:key name="group" match="foo" use="concat(@name, '|' , @version)"/>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<xsl:apply-templates select="foobar/foo[generate-id() =
generate-id(key('group', concat(@name, '|' , @version)))]"/>
</xsl:template>
<xsl:template match="foo">
<xsl:element name="group">
<xsl:attribute name="name"><xsl:apply-templates
select="@*"/></xsl:attribute>
</xsl:element>
</xsl:template>
<xsl:template match="@*">
<xsl:value-of select="."/>
</xsl:template>
</xsl:stylesheet>
changes the name of the elements to "group" and then recursively creates
a string value for the attribute "name" bringing all the attributes into
one group name. So you get XML output that looks like this...
<?xml version="1.0" encoding="UTF-8"?>
<group name="a1"/>
<group name="b1"/>
<group name="b2"/>
<group name="c1"/>
By using Andreas method of creating a variable for later use (wrap an
xsl:variable element around the apply-templates of the first template
and give it a name for future reference) and then converting that
variable to a node-set (using the select statement within another
variable) will allow you access to that node-set for future use within
your template(s).
And now after writing all this Ive realized that I have probably
confused more than ive done good. However, for future reference this
may be helpful so I will go ahead and send it just in case it is.
Best of luck!
<M:D/>
-----Original Message-----
From: Nicolas Mailhot [mailto:Nicolas(_dot_)Mailhot(_at_)laPoste(_dot_)net]
Sent: Sunday, April 11, 2004 8:14 AM
To: xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com
Subject: [xsl] First element with given attribute values
Hi,
I find that very often I end up with lists of elements like:
<foo name="a" version="1"/>
<foo name="b" version="1"/>
<foo name="a" version="1"/>
<foo name="b" version="2"/>
<foo name="c" version="1"/>
<foo name="b" version="1"/>
<foo name="b" version="1"/>
Which I need to trim, keeping only the first element with an unique
attibute value, or unique attribute values. For example, if I only
wanted the first element with an unique name,version pair this would
give :
<foo name="a" version="1"/>
<foo name="b" version="1"/>
<foo name="b" version="2"/>
<foo name="c" version="1"/>
Is there a clean way to do it ?
<xsl:template match="foo[(_at_)name=(_dot_)/@name and @version=./@version][1]">
only matches the first
<foo name="a" version="1"/>
Cheers,
--
Nicolas Mailhot