[ACCEPTED]-How to count distinct values in a node?-xslt-grouping

Accepted answer
Score: 27

If you have a large document, you probably 9 want to use the "Muenchian Method", which 8 is usually used for grouping, to identify 7 the distinct nodes. Declare a key that indexes 6 the things you want to count by the values 5 that are distinct:

<xsl:key name="artists-by-country" match="Artist_by_Country" use="Country" />

Then you can get the <Artist_by_Country> elements 4 that have distinct countries using:

/Artists_by_Countries
  /Artist_by_Country
    [generate-id(.) =
     generate-id(key('artists-by-country', Country)[1])]

and you 3 can count them by wrapping that in a call 2 to the count() function.

Of course in XSLT 2.0, it's 1 as simple as

count(distinct-values(/Artists_by_Countries/Artist_by_Country/Country))
Score: 6

In XSLT 1.0 this isn't obvious, but the 5 following should give you an idea of the 4 requirement:

count(//Artist_by_Country[not(Location_ID=preceding-sibling::Artist_by_Country/Location_ID)]/Location_ID)

The more elements in your XML 3 the longer this takes, as it checks every 2 single preceding sibling of every single 1 element.

Score: 5

Try something like this:

count(//Country[not(following::Country/text() = text())])

"Give me the 5 count of all Country nodes without a following 4 Country with matching text"

The interesting 3 bit of that expression, IMO, is the following axis.

You 2 could probably also remove the first /text(), and 1 replace the second with .

Score: 0

If you have control of the xml generation 6 on the first occurence of a country you 5 could add an attribute to the country node 4 such as distinct='true' flag the country 3 as "used" and not subsequently add the distinct 2 attribute if you come across that country 1 again.

You could then do

<xsl:for-each select="Artists_by_Countries/Artist_by_Country/Country[@distinct='true']" />

More Related questions