Count the frequency of specific nodes in an XML document
This may have been covered before, but after much googling, I can't seem to find any examples. Essentially I'm trying to get a frequency count of the number of time a book is taken out on loan. My XML tree is given below, along with the XSL and resulting output.
<?xml-stylesheet type="text/xsl" href="LoanStyler.xsl"?>
<loans>
<loan id="0001">
<summary>
<user>AAA</user>
<dateOut>2011-01-01</dateOut>
<dateDue>2011-01-14</dateDue>
</summary>
<details>
<books>
<name>Book7</name>
<name>Book4</name>
</books>
</details>
</loan>
<loan id="0002">
<summary>
<user>BBB</user>
<dateOut>2011-01-10</dateOut>
<dateDue>2011-01-24</dateDue>
</summary>
<details>
<books>
<name>Book1</name>
<name>Book2</name>
<name>Book4</name>
<name>Book6</name>
</books>
</details>
</loan>
<loan id="0003">
<summary>
<user>CCC</user>
<dateOut>2011-01-14</dateOut>
<dateDue>2011-01-28</dateDue>
</summary>
<details>
<books>
<name>Book1</name>
<name>Book3</name>
<name>Book4</name>
<name>Book7</name>
<name>Book8</name>
</books>
</details>
</loan>
<loan id="0004">
<summary>
<user>DDD</user>
<dateOut>2011-02-01</dateOut>
<dateDue>2011-02-14</dateDue>
</summary>
<details>
<books>
<name>开发者_Go百科;Book1</name>
<name>Book2</name>
<name>Book4</name>
</books>
</details>
</loan>
</loans>
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key
name="books-by-name"
match="//loans/loan/details/books"
use="name"
/>
<xsl:template match="/">
<html>
<body>
<h1>Loan Records Log</h1>
<table Border="1">
<tr>
<th>Loan ID</th>
<th>User</th>
<th>Date Out</th>
<th>Date Due</th>
</tr>
<xsl:for-each select="//loans/loan">
<tr>
<td><xsl:value-of select="@id"/></td>
<td><xsl:value-of select="summary/user"/></td>
<td><xsl:value-of select="summary/dateOut"/></td>
<td><xsl:value-of select="summary/dateDue"/></td>
</tr>
</xsl:for-each>
</table>
<table Border="1">
<tr>
<th>Book name</th>
<th>Count</th>
</tr>
<xsl:for-each select="books[count(. | key('books-by-name', name)[1]) = 1]">
<tr>
<td><xsl:value-of select="name" /></td>
<td><xsl:value-of select="count(key('books-by-name', name))" /></td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Loan Records Log
Loan ID User Date Out Date Due
0001 AAA 2011-01-01 2011-01-14
0002 BBB 2011-01-10 2011-01-24
0003 CCC 2011-01-14 2011-01-28
0004 DDD 2011-02-01 2011-02-14
Book name Count
As you can see the attempt at Muenchian Grouping doesn't seem to be working. Could someone please explain what I'm doing wrong, as the only examples I can find don't appear to have helped.
The problem is here:
<xsl:for-each select="books
[count(. | key('books-by-name', name)[1]) = 1]">
Must be:
<xsl:for-each select="loans/loan/details/books
[count(. | key('books-by-name', name)[1]) = 1]">
At the location the above instruction is specified, the current node is/
and /
doesn't have a child element books
.
Also, there is a logic error. The key must be different.
Here is a corrected solution:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="books-by-name"
match="books/name" use="." />
<xsl:template match="/">
<html>
<body>
<h1>Loan Records Log</h1>
<table Border="1">
<tr>
<th>Loan ID</th>
<th>User</th>
<th>Date Out</th>
<th>Date Due</th>
</tr>
<xsl:for-each select="//loans/loan">
<tr>
<td>
<xsl:value-of select="@id"/>
</td>
<td>
<xsl:value-of select="summary/user"/>
</td>
<td>
<xsl:value-of select="summary/dateOut"/>
</td>
<td>
<xsl:value-of select="summary/dateDue"/>
</td>
</tr>
</xsl:for-each>
</table>
<table Border="1">
<tr>
<th>Book name</th>
<th>Count</th>
</tr>
<xsl:for-each select="loans/loan/details/books/name
[count(. | key('books-by-name', name)[1]) = 1]">
<tr>
<td>
<xsl:value-of select="." />
</td>
<td>
<xsl:value-of select="count(key('books-by-name',.))" />
</td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
when this transformation is applied on the provided XML document:
<loans>
<loan id="0001">
<summary>
<user>AAA</user>
<dateOut>2011-01-01</dateOut>
<dateDue>2011-01-14</dateDue>
</summary>
<details>
<books>
<name>Book7</name>
<name>Book4</name>
</books>
</details>
</loan>
<loan id="0002">
<summary>
<user>BBB</user>
<dateOut>2011-01-10</dateOut>
<dateDue>2011-01-24</dateDue>
</summary>
<details>
<books>
<name>Book1</name>
<name>Book2</name>
<name>Book4</name>
<name>Book6</name>
</books>
</details>
</loan>
<loan id="0003">
<summary>
<user>CCC</user>
<dateOut>2011-01-14</dateOut>
<dateDue>2011-01-28</dateDue>
</summary>
<details>
<books>
<name>Book1</name>
<name>Book3</name>
<name>Book4</name>
<name>Book7</name>
<name>Book8</name>
</books>
</details>
</loan>
<loan id="0004">
<summary>
<user>DDD</user>
<dateOut>2011-02-01</dateOut>
<dateDue>2011-02-14</dateDue>
</summary>
<details>
<books>
<name>Book1</name>
<name>Book2</name>
<name>Book4</name>
</books>
</details>
</loan>
</loans>
the wanted, correct result is produced:
<html>
<body>
<h1>Loan Records Log</h1>
<table Border="1">
<tr>
<th>Loan ID</th>
<th>User</th>
<th>Date Out</th>
<th>Date Due</th>
</tr>
<tr>
<td>0001</td>
<td>AAA</td>
<td>2011-01-01</td>
<td>2011-01-14</td>
</tr>
<tr>
<td>0002</td>
<td>BBB</td>
<td>2011-01-10</td>
<td>2011-01-24</td>
</tr>
<tr>
<td>0003</td>
<td>CCC</td>
<td>2011-01-14</td>
<td>2011-01-28</td>
</tr>
<tr>
<td>0004</td>
<td>DDD</td>
<td>2011-02-01</td>
<td>2011-02-14</td>
</tr>
</table>
<table Border="1">
<tr>
<th>Book name</th>
<th>Count</th>
</tr>
<tr>
<td>Book7</td>
<td>2</td>
</tr>
<tr>
<td>Book4</td>
<td>4</td>
</tr>
<tr>
<td>Book1</td>
<td>3</td>
</tr>
<tr>
<td>Book2</td>
<td>2</td>
</tr>
<tr>
<td>Book4</td>
<td>4</td>
</tr>
<tr>
<td>Book6</td>
<td>1</td>
</tr>
<tr>
<td>Book1</td>
<td>3</td>
</tr>
<tr>
<td>Book3</td>
<td>1</td>
</tr>
<tr>
<td>Book4</td>
<td>4</td>
</tr>
<tr>
<td>Book7</td>
<td>2</td>
</tr>
<tr>
<td>Book8</td>
<td>1</td>
</tr>
<tr>
<td>Book1</td>
<td>3</td>
</tr>
<tr>
<td>Book2</td>
<td>2</td>
</tr>
<tr>
<td>Book4</td>
<td>4</td>
</tr>
</table>
</body>
</html>
精彩评论