tags:

views:

192

answers:

3

ok i have this xml

<roots>
<root>
    <name>first</name>
    <item type='test'><something>A</something></item>
    <item type='test'><something>B</something></item>
    <item type='test'><something>C</something></item>
    <item type='test'><something>A</something></item>
    <item type='other'><something>A</something></item>
    <item type='test'><something>B</something></item>
    <item type='other'><something>D</something></item>

</root>
<root>
<name>second</name>
    <item type='test'><something>E</something></item>
    <item type='test'><something>B</something></item>
    <item type='test'><something>F</something></item>
    <item type='test'><something>A</something></item>
    <item type='other'><something>A</something></item>
    <item type='test'><something>B</something></item>
    <item type='other'><something>D</something></item>

</root>

</roots>

now i need to get the unique values of each root node so far i have

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;

  <xsl:output indent="yes" method="text"/>
  <xsl:key name="item-by-value" match="something" use="."/>
<xsl:key name="rootkey" match="root" use="name"/>

  <xsl:template match="/">
 <xsl:for-each select="key('rootkey','second')">


<xsl:for-each select="item/something">
  <xsl:if test="generate-id() = generate-id(key('item-by-value', normalize-space(.)))">
  <xsl:value-of select="."/>
 </xsl:if>
</xsl:for-each> 
</xsl:for-each>

</xsl:template>


</xsl:stylesheet>

if i use "First" as the key to get only the first root i get a good result ABCD

how ever if i use "second" i only get EF but i need the result to be ABDFE

A: 

I think you're pretty close. But you only want the first value of the item-by-value key which has the correct root as parent:

<xsl:for-each select="key('rootkey','second')">
    <xsl:variable name="root" select="generate-id()" />
    <xsl:for-each select="item/something">
        <xsl:sort order="ascending" select="." data-type="text"/>
        <xsl:if test="generate-id() = generate-id(key('item-by-value', .)[generate-id(ancestor::root)=$root][1])">
            <xsl:value-of select="."/>
        </xsl:if>
    </xsl:for-each>
</xsl:for-each>
Lucero
yeah been close for quite some time haha, and even with the [1] i still get the same results
Nathan
There's no need to be rude when someone tries to help. I misunderstood the "unique" part of the question at first. I made a small change to my code to reflect the wanted result.
Lucero
+1  A: 

This is a case where you must use a compound key.

This transformation:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
 <xsl:output method="text"/>

 <xsl:key name="kSomethingByNameAndVal" match="something"
  use="concat(../../name, '+', .)"/>

 <xsl:template match="/">
   <xsl:for-each select="*/*">
     <xsl:for-each select=
      "item/something
             [generate-id()
             =
              generate-id(key('kSomethingByNameAndVal',
                               concat(../../name, '+', .)
                              )
                          )
             ]
      ">

       <xsl:value-of select="."/>
     </xsl:for-each>
     <xsl:text>&#xA;</xsl:text>
   </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>

when applied on the provided XML document correctly produces the wanted result:

ABCD

EBFAD

Dimitre Novatchev
+1  A: 

I get EBFAD with a slight modification of your xsl. The key is that if you're using the key to find the first node with this content under the given root element, then the key needs to be specific to the root element. I changed the xsl:key to:

<xsl:key name="item-by-value" match="something"
 use="concat(normalize-space(.), ' ', generate-id(./ancestor::root))"/>

Then the xsl:if test becomes:

<xsl:if test="generate-id() = generate-id(key('item-by-value', 
                  concat(normalize-space(.), ' ', generate-id(./ancestor::root))))">
Daniel Martin