Q:

XSLT/XPath to count the most commonly used words

Say I have an XML document like this:

<library xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="library.xsd">
<book>
    <title>Harry Potter Sorcerer's Stone</title>
    <artist>J.K. Rowling</artist>
</book>
<book>
    <title>Harry Potter Chamber of Secrets</title>
    <artist>J.K. Rowling</artist>
</book>
<book>
    <title>Harry Potter Prisoner of Azkaban</title>
    <artist>J.K. Rowling</artist>
</book>     
</library>

I want my XSLT document to find the 3 most commonly used words amongst the titles, and their counts. (So I want to output: "Harry": 3, "Potter": 3, "of": 2).
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<h2>3 Most Commonly Used Words</h2>
<ul>
   <li>Word - Count</li>
</ul>
</xsl:template>
</xsl:stylesheet>

I'm an XML beginner and unclear how to do aggregation using XSLT and XPath. I was thinking some combination of tokenize() and sum()? Can someone point me in the right direction?

A:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:output indent="yes"/>
    <xsl:template match="/">
        <h2>3 Most Commonly Used Words</h2>
        <ul>
        <xsl:for-each-group group-by="." select="
            for $w in //title/tokenize(., '\W+') return $w">
            <xsl:sort select="count(current-group())" order="descending" />
            <xsl:if test="position() lt 4">
                <li>
                    <xsl:value-of select="current-grouping-key()"/>
                    <xsl:text> - </xsl:text>
                    <xsl:value-of select="count(current-group())"/>
                </li>
            </xsl:if>
        </xsl:for-each-group>
        </ul>
    </xsl:template>
</xsl:stylesheet>

