RE: [xsl] First element with given attribute values

Subject: RE: [xsl] First element with given attribute values
From: "M. David Peterson" <m.david@xxxxxxxxxx>
Date: Sun, 11 Apr 2004 09:16:57 -0600
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.Mailhot@xxxxxxxxxxx] 
Sent: Sunday, April 11, 2004 8:14 AM
To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
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[@name=./@name and @version=./@version][1]">

only matches the first

<foo name="a" version="1"/>

Cheers,

-- 
Nicolas Mailhot

Current Thread