Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations derfloh on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

XSLT, select unique nodes from element list

Status
Not open for further replies.

johnstm

Programmer
Joined
Apr 8, 2004
Messages
5
Location
GB
Hi All!

I have XML the looks like this
<Responsibility>
<Collaborators>
<Collaborator>car</Collaborator>
<Collaborator>wheel</Collaborator>
</Collaborators>
</Responsibility>

<Responsibility>
<Collaborators>
<Collaborator>car</Collaborator>
</Collaborators>
</Responsibility>

Ok so what i need to do is get all the collaborators from the XML but i only want to get them once! So if i have output car i don't want to output it again!

so the output i want from the preceding XML is

car
wheel

The way i thought i could do it was sort a list of collaborators using <xsl:sort> and then for each collaborator have an if condition that says if this collaborator equals the last collaborator in the list then don't output! However i am having trouble getting this to work any ideas??
 
Here is a simple example based on your xml file
which demonstrates one way of solving your problem:

Code:
<?xml version="1.0"?>
<file>
   <Responsibility>
      <Collaborators>
         <Collaborator>car</Collaborator>
         <Collaborator>wheel</Collaborator>
       </Collaborators>
   </Responsibility>
   <Responsibility>
      <Collaborators>
         <Collaborator>car</Collaborator>
      </Collaborators>
   </Responsibility>
</file>

Code:
<?xml version="1.0" encoding="ISO-8859-1" ?>
 
<xsl:stylesheet version="1.0" 
     xmlns:xsl="[URL unfurl="true"]http://www.w3.org/1999/XSL/Transform">[/URL]

<xsl:output method="html"/>

  <xsl:key name="cr" match="Collaborator" use="."/>

  <xsl:template match="/">
     <xsl:apply-templates select="//Collaborator[generate-id() = generate-id(key('cr', .)[1])]">
        <xsl:sort select="." />
     </xsl:apply-templates>
  </xsl:template>

  <xsl:template match="Collaborator">
     Output: <xsl:value-of select="."/>
  </xsl:template>

</xsl:stylesheet>
 
How about this?
Code:
<xsl:for-each select="//Responsibility/Collaborators/Collaborator[not(.=preceding::Collaborator)]">
  <xsl:value-of select="."/>
</xsl:for-each>
 
But on second thoughts: fpmurphy is right to use a key, it is probably faster.
You don't need to use the generate-id though: you can also test wether your node is the same as the first in the key-list this way:
Code:
<xsl:for-each select="//Responsibility/Collaborators/Collaborator[count(.|key('cr', .)[1])=1]">
  <xsl:value-of select="." />
</xsl:for-each>
 
Guys thats awesome thanks so much for your help!
 
I am running this from VB.nets XML Parser (XMLTransform Object) and i can't get the XSL script to load! Any ideas??
 
I have figured it out was some problem with the way i was trying to run your code! Thanks again guys
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top