N. America: 800 876 3101 | World: 44 (0) 1753 218 930

Can I group results based on values?

I have a list of books in XML, and I would like to generate a different XML structure that groups all books per subject; this is my source XML:

<books>
    <book bookid="1">
        <title>Java Web Services</title>
        <subject>XML</subject>
    </book>
    <book bookid="2">
        <title>XML Applications</title>
        <subject>XML</subject>
    </book>
    <book bookid="4">
        <title>Beginning Visual C++ 6 Database Programming</title>
        <subject>Database</subject>
    </book>
    <book bookid="5">
        <title>Beginner&apos;s Guide to Access 2.0</title>
        <subject>Database</subject>
    </book>
</books>

I know in XSLT 2.0 has a way to do that easily using xsl:for-each-group, like this:

<subjects>
    <xsl:for-each-group select="/books/book" group-by="subject">
        <subject name="{subject}">
            <xsl:for-each select="current-group()">
                <book-title><xsl:value-of select="title"/></book-title>
            </xsl:for-each>
        </subject>
    </xsl:for-each-group>
</subjects>

How can I do the same using XQuery 1.0?

Even if XQuery 1.0 doesn’t have the explicit language support for value-based grouping that XSLT 2.0 has, you can easily implement grouping using the fn:distinct-values() function and the other XQuery language structures. Your example can be re-written in XQuery this way:

<subjects> {
    for $subject in distinct-values(/books/book/subject)
    let $books-in-group := /books/book[subject=$subject]
    return
        <subject name="{$subject}"> {
            for $book in $books-in-group
            return
                <book-title>{$book/title/text()}</book-title>
        } </subject>
} </subjects>

See the XQuery W3C specifications for more details on this and other grouping functions.


Next Question!

When should I use /text() at the end of my XPath expression?

Submit Your DataDirect XQuery Tip or Trick

Tell us your XQuery Tip or Trick – if it gets published on our site, you’ll receive a

$10.00 Amazon.com
Gift Certificate!

Submit your tip or trick today.