|
>Home>Learn XQuery> XQuery Tips and Tricks>Value Based Grouping
Print
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'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?
|