Unique XSL values ​​on node

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 unique values ​​for each root of the node, as long as I have

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

  <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 a key to get only the first root, I get a good ABCD result

be that as it may, if I use the "second", I get only EF, but I need an ABDFE result

+5
source share
3 answers

I get EBFADwith a slight modification to your xsl. The key is that if you use the key to search for the first node with this content under the given root element, then the key must be specific to the root element. I changed xsl:keyto:

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

xsl:if :

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

, .

:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <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>

XML- :

ABCD

EBFAD

+2

I think you are pretty close. But you only need the first value of the item-by-value key, which has the correct root as the 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>
0
source

All Articles