Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Count distinct on multiple elements with XSLT

This is a follow up question to Grouping & counting by two XML elements with XSLT

This is my input XML:

<root>
    <cust>
        <firstname>bob</firstname>
        <lastname>smith</lastname>
        <age>40</age>
    </cust>
    <cust>
        <firstname>joe</firstname>
        <lastname>smith</lastname>
        <age>75</age>
    </cust>
    <cust>
        <firstname>joe</firstname>
        <lastname>brown</lastname>
        <age>25</age>
    </cust>
    <cust>
        <firstname>pete</firstname>
        <lastname>smith</lastname>
        <age>40</age>
    </cust>
</root>

After processing it with this XSLT:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

<xsl:key name="cust" match="cust" use="concat(lastname, age)"/>
<xsl:key name="dist_cnt" match="/root/cust/lastname/text()" use="."/>

<xsl:template match="/root">
    <html>
        <body>
            <table border="1">
                <tr>
                    <th>Name</th>
                    <th>Age</th>
                    <th>#</th>
                </tr>
                <xsl:for-each select="cust[count(. | key('cust', concat(lastname, age))[1]) = 1]">
                    <xsl:sort select="lastname"/>
                    <tr>
                        <td>
                            <xsl:value-of select="lastname"/>
                        </td>
                        <td>
                            <xsl:value-of select="age"/>
                        </td>
                        <td>
                            <xsl:value-of select="count(key('cust', concat(lastname, age)))"/>
                        </td>
                    </tr>
                </xsl:for-each>
            </table>
            Total distinct (lastname only): <xsl:value-of select="count(/root/cust/lastname/text()[generate-id() = generate-id(key('dist_cnt',.)[1])])"/>
        </body>
    </html>
</xsl:template>

The result is as follows

Name    Age #
brown   25  1
smith   40  2
smith   75  1

Total distinct (lastname only): 2

What I’m really interested in is the number 3, the number of rows of the output table.

The result "Total distinct (lastname only): 2" is just my first attempt at reaching that goal. It shows that I have managed to count the distinct number of lastname’s. But I didn’t get any further than that.

I’d like the result to be the total number of distinct lastname/age combinations.

>Solution :

It can be much simpler than you’re making it:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:key name="cust" match="cust" use="concat(lastname, age)"/>

<xsl:template match="/root">
    <xsl:variable name="distinct-customers" select="cust[count(. | key('cust', concat(lastname, age))[1]) = 1]" />
    <html>
        <body>
            <table border="1">
                <tr>
                    <th>Name</th>
                    <th>Age</th>
                    <th>#</th>
                </tr>
                <xsl:for-each select="$distinct-customers">
                    <xsl:sort select="lastname"/>
                    <tr>
                        <td>
                            <xsl:value-of select="lastname"/>
                        </td>
                        <td>
                            <xsl:value-of select="age"/>
                        </td>
                        <td>
                            <xsl:value-of select="count(key('cust', concat(lastname, age)))"/>
                        </td>
                    </tr>
                </xsl:for-each>
            </table>
            <xsl:text>Total distinct: </xsl:text>
            <xsl:value-of select="count($distinct-customers)"/>
        </body>
    </html>
</xsl:template>

</xsl:stylesheet>
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading