tags:

views:

98

answers:

3

I have an xml document that contains some "Item" elements with ids. I want to make a list of the unique Item ids. The Item elements are not in a list though - they can be at any depth within the xml document - for example:


<Node>
  <Node>
    <Item id="1"/>
    <Item id="2"/>
  </Node>
  <Node>
    <Item id="1"/>
    <Node>
      <Item id="3"/>
    </Node>
  </Node>
  <Item id="2"/>
</Node>

I would like the output 1,2,3 (or a similar representation). If this can be done with a single xpath then even better!

I have seen examples of this for lists of sibling elements, but not for a general xml tree structure. I'm also restricted to using xslt 1.0 methods. Thanks!

+5  A: 

Try this (using Muenchian grouping):

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
    <xsl:key name="item-id" match="Item" use="@id" />
    <xsl:template match="/Node">
        <xsl:for-each select="//Item[count(. | key('item-id', @id)[1]) = 1]">
            <xsl:value-of select="@id" />,
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>
Rubens Farias
//Item[generate-id() = generate-id(key('item-id', @id)[1]))] is more concise and less time consuming.
Erlock
interesting, I didnt knew that, ty!
Rubens Farias
A: 

Not sure if this is what you mean, but just in case.

In the html

<xsl:apply-templates select="item"/>

The template.

 <xsl:template match="id">
        <p>
        <xsl:value-of select="@id"/> - 
        <xsl:value-of select="."/> 
        </p>
    </xsl:template>
Cesar Lopez
that will not to work, as you don't have an `id` element; OP wants unique @id values to be displayed
Rubens Farias
+3  A: 

Selecting all unique items with a single XPath expression (without indexing, beware of performance issues):

//Item[not(@id = preceding::Item/@id)]
Erlock