Search code examples
xmlxsltxslt-grouping

Return distinct nodes in XSLT


I need help on how to loop for each unique node "set". The result I expect are unique sets. I've tried many different ways but nothing. It seems that I'm always getting all results, or none.

 <Res>
        <ResQ>
            <set>
                <No>1</No>
                <Desc>test</Desc>
                <Num>123</Num>
            </set>
            <set>
                <No>2</No>
                <Desc>test</Desc>
                <Num>111</Num>
            </set>
            <set>
                <No>3</No>
                <Desc>test</Desc>
                <Num>100</Num>
            </set>
        </ResQ>
    </Res>
    <Res>
        <ResQ>
            <set>
                <No>1</No>
                <Desc>test</Desc>
                <Num>333</Num>
            </set>
            <set>
                <No>2</No>
                <Desc>test</Desc>
                <Num>123</Num>
            </set>
            <set>
                <No>3</No>
                <Desc>test</Desc>
                <Num>555</Num>
            </set>
        </ResQ>
    </Res>

I've tried this but with no desired results.

<xsl:key name="keyTest" match="//set" use="concat(No, '+', Desc,'+',Num)"/> 

<xsl:for-each select="//set[generate-id(.) = generate-id(key('keyTest', concat(No, '+', Desc,'+',Num))[1])]" >
        <xsl:call-template name="row">
                    <xsl:with-param name="rb" select="No" />
                    <xsl:with-param name="desc" select="Desc" />
                    <xsl:with-param name="number" select="Num" />
         </xsl:call-template>
</xsl:for-each>

Solution

  • If two sets are considered equals when they have the same Num, you should use just that element in both the key declaration and its use (otherwise, I didn't understand the question and my answer is useless):

    <xsl:key name="keyTest" match="//set" use="Num"/>
    ...
    <xsl:for-each select="//set[generate-id(.) = generate-id(key('keyTest', Num)[1])]" >
        <xsl:call-template name="row">
            <xsl:with-param name="rb" select="No" />
            <xsl:with-param name="desc" select="Desc" />
            <xsl:with-param name="number" select="Num" />
        </xsl:call-template>
    </xsl:for-each>