我是XSLT的初学者,对Muenchian分组方法感到困惑。 这是我的XML文档
<?xml version='1.0'?>
<?xml-stylesheet type="text/xsl" href="test.xslt"?>
<catalog>
<cd PurchaseDate="20000101">
<title>Empire Burlesque</title>
<artist>Bob Dylan</artist>
<country>USA</country>
<quantity>20</quantity>
<price>10.90</price>
</cd>
<cd PurchaseDate="20000101">
<title>Hide your heart</title>
<artist>Bonnie Tyler</artist>
<country>UK</country>
<quantity>10</quantity>
<price>9.90</price>
</cd>
<cd PurchaseDate="20000102">
<title>Greatest Hits</title>
<artist>Dolly Parton</artist>
<country>USA</country>
<quantity>15</quantity>
<price>9.90</price>
</cd>
<cd PurchaseDate="20000101">
<title>Still got the blues</title>
<artist>Gary Moore</artist>
<country>UK</country>
<quantity>5</quantity>
<price>10.20</price>
</cd>
<cd PurchaseDate="20000103">
<title>Eros</title>
<artist>Eros Ramazzotti</artist>
<country>EU</country>
<quantity>6</quantity>
<price>9.90</price>
</cd>
<cd PurchaseDate="20000103">
<title>One night only</title>
<artist>Bee Gees</artist>
<country>UK</country>
<quantity>16</quantity>
<price>10.90</price>
</cd>
<cd PurchaseDate="20000102">
<title>Sylvias Mother</title>
<artist>Dr.Hook</artist>
<country>UK</country>
<quantity>3</quantity>
<price>8.10</price>
</cd>
<cd PurchaseDate="20000101">
<title>Maggie May</title>
<artist>Rod Stewart</artist>
<country>UK</country>
<quantity>8</quantity>
<price>8.50</price>
</cd>
<cd PurchaseDate="20000103">
<title>Romanza</title>
<artist>Andrea Bocelli</artist>
<country>EU</country>
<quantity>30</quantity>
<price>10.80</price>
</cd>
</catalog>
和XSLT
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" indent="yes" />
<xsl:key name="kByCountry" match="cd" use="country" />
<xsl:output method="html" />
<xsl:template match="catalog">
<html>
<body>
<table border="1">
<xsl:for-each select="cd[count(.|key('kByCountry',country)[1]) = 1]">
<xsl:sort select="country" />
<tr bgcolor="#9acd32">
<td colspan="4">Country:<xsl:value-of select="country" /></td>
</tr>
<tr>
<td>Purchase Date</td>
<td>Quantity</td>
<td>Unit Price</td>
<td>Total</td>
</tr>
<tr>
<td>?date?</td>
<td><xsl:value-of select="quantity" /> </td>
<td><xsl:value-of select="price" /></td>
<td><xsl:value-of select="price*quantity" /></td>
</tr>
<tr>
<td colspan="3" align="right">Sub-total</td>
<td>?how to count subtotal together?</td>
</tr>
</xsl:for-each>
<tr>
<td colspan="3" align="right">Grand-total</td>
<td>?how to count all subtotal together?</td>
</tr>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
我的问题是如何列出国家/地区组中的所有购买日期。这样我就能计算出国家之后的总金额
答案 0 :(得分:1)
此转化:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common" exclude-result-prefixes="ext">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:key name="kCDPurchByCountryDate" match="cd"
use="concat(@PurchaseDate,'+', country)"/>
<xsl:template match="/">
<xsl:variable name="vrtfPass1">
<xsl:apply-templates/>
</xsl:variable>
<xsl:apply-templates select="ext:node-set($vrtfPass1)/*">
<xsl:sort select="@country"/>
<xsl:sort select="@PurchaseDate" order="descending"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match=
"cd[generate-id()
=generate-id(key('kCDPurchByCountryDate',
concat(@PurchaseDate,'+', country)
)[1]
)]">
<trans country="{country}" PurchaseDate="{@PurchaseDate}">
<amount><xsl:value-of select="quantity*price"/></amount>
<xsl:apply-templates mode="group" select=
"key('kCDPurchByCountryDate',concat(@PurchaseDate,'+', country))
[position() > 1]
"/>
</trans>
</xsl:template>
<xsl:template match="cd" mode="group">
<amount><xsl:value-of select="quantity*price"/></amount>
</xsl:template>
<xsl:template match="text()"/>
<xsl:template match="trans">
<xsl:copy>
<xsl:copy-of select="@*"/>
<total><xsl:value-of select="sum(amount)"/></total>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
应用于提供的XML文档时:
<catalog>
<cd PurchaseDate="20000101">
<title>Empire Burlesque</title>
<artist>Bob Dylan</artist>
<country>USA</country>
<quantity>20</quantity>
<price>10.90</price>
</cd>
<cd PurchaseDate="20000101">
<title>Hide your heart</title>
<artist>Bonnie Tyler</artist>
<country>UK</country>
<quantity>10</quantity>
<price>9.90</price>
</cd>
<cd PurchaseDate="20000102">
<title>Greatest Hits</title>
<artist>Dolly Parton</artist>
<country>USA</country>
<quantity>15</quantity>
<price>9.90</price>
</cd>
<cd PurchaseDate="20000101">
<title>Still got the blues</title>
<artist>Gary Moore</artist>
<country>UK</country>
<quantity>5</quantity>
<price>10.20</price>
</cd>
<cd PurchaseDate="20000103">
<title>Eros</title>
<artist>Eros Ramazzotti</artist>
<country>EU</country>
<quantity>6</quantity>
<price>9.90</price>
</cd>
<cd PurchaseDate="20000103">
<title>One night only</title>
<artist>Bee Gees</artist>
<country>UK</country>
<quantity>16</quantity>
<price>10.90</price>
</cd>
<cd PurchaseDate="20000102">
<title>Sylvias Mother</title>
<artist>Dr.Hook</artist>
<country>UK</country>
<quantity>3</quantity>
<price>8.10</price>
</cd>
<cd PurchaseDate="20000101">
<title>Maggie May</title>
<artist>Rod Stewart</artist>
<country>UK</country>
<quantity>8</quantity>
<price>8.50</price>
</cd>
<cd PurchaseDate="20000103">
<title>Romanza</title>
<artist>Andrea Bocelli</artist>
<country>EU</country>
<quantity>30</quantity>
<price>10.80</price>
</cd>
</catalog>
会产生想要的正确结果:
<trans country="EU" PurchaseDate="20000103">
<total>383.4</total>
</trans>
<trans country="UK" PurchaseDate="20000103">
<total>174.4</total>
</trans>
<trans country="UK" PurchaseDate="20000102">
<total>24.299999999999997</total>
</trans>
<trans country="UK" PurchaseDate="20000101">
<total>218</total>
</trans>
<trans country="USA" PurchaseDate="20000102">
<total>148.5</total>
</trans>
<trans country="USA" PurchaseDate="20000101">
<total>218</total>
</trans>
<强>解释强>:
这是非递归,两遍转换。对于递增XSLT 1.0的乘法数字乘法解决方案,然后对乘法的结果求和,请参阅此问题的答案: Multiply 2 numbers and then sum with XSLT :
第一次按国家/地区和购买日期分组,使用 Muenchian grouping method 和复合键。
对于每个组,会生成多个amount
元素。
第二遍浅层复制第一遍中创建的transaction
元素。它使用单个amount
元素替换total
个孩子。
<强> II。 XSLT 2.0解决方案:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/*">
<xsl:for-each-group select="cd" group-by="concat(country,'+',@PurchaseDate)">
<xsl:sort select="country"/>
<xsl:sort select="@PurchaseDate" order="descending"/>
<trans country="{country}" PurchaseDate="{@PurchaseDate}">
<total><xsl:sequence select="sum(current-group()/(price*quantity))"/></total>
</trans>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>
答案 1 :(得分:0)
虽然您没有展示出您期望看到的内容,但我认为这是一个解决方案,可以满足您的需求。请注意,不需要<xsl:for-each>
;这个基于<xsl:template>
的解决方案更灵活。
当这个XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kCdByCountry" match="cd" use="country"/>
<xsl:template match="/*">
<html>
<body>
<table border="1">
<xsl:apply-templates
select="cd[generate-id() =
generate-id(key('kCdByCountry', country)[1])]">
<xsl:sort select="country"/>
</xsl:apply-templates>
<tr bgcolor="#9acd32">
<td colspan="4">
<xsl:text>Total: </xsl:text>
<xsl:call-template name="sumProducts">
<xsl:with-param name="pElemList" select="/*/*"/>
</xsl:call-template>
</td>
</tr>
</table>
</body>
</html>
</xsl:template>
<xsl:template match="cd">
<tr bgcolor="#9acd32">
<td colspan="4">
<xsl:text>Country: </xsl:text>
<xsl:value-of select="country"/>
</td>
</tr>
<tr>
<td>Purchase Date</td>
<td>Quantity</td>
<td>Unit Price</td>
<td>Total</td>
</tr>
<xsl:apply-templates select="key('kCdByCountry', country)" mode="values">
<xsl:sort select="@PurchaseDate" data-type="number"/>
</xsl:apply-templates>
<tr bgcolor="#9acd32">
<td colspan="4">
<xsl:text>Subtotal: </xsl:text>
<xsl:call-template name="sumProducts">
<xsl:with-param
name="pElemList"
select="key('kCdByCountry', country)"/>
</xsl:call-template>
</td>
</tr>
</xsl:template>
<xsl:template match="cd" mode="values">
<tr>
<td>
<xsl:value-of select="@PurchaseDate"/>
</td>
<td>
<xsl:value-of select="quantity"/>
</td>
<td>
<xsl:value-of select="price"/>
</td>
<td>
<xsl:value-of select="quantity * price"/>
</td>
</tr>
</xsl:template>
<xsl:template name="sumProducts">
<xsl:param name="pElemList"/>
<xsl:param name="pTotal" select="0"/>
<xsl:choose>
<xsl:when test="$pElemList">
<xsl:variable name="vCurrentElem" select="$pElemList[1]"/>
<xsl:call-template name="sumProducts">
<xsl:with-param
name="pElemList"
select="$pElemList[position() > 1]"/>
<xsl:with-param
name="pTotal"
select="$pTotal + $vCurrentElem/price * $vCurrentElem/quantity"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$pTotal"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
...适用于提供的XML:
<?xml version="1.0" encoding="UTF-8"?>
<catalog>
<cd PurchaseDate="20000101">
<title>Empire Burlesque</title>
<artist>Bob Dylan</artist>
<country>USA</country>
<quantity>20</quantity>
<price>10.90</price>
</cd>
<cd PurchaseDate="20000101">
<title>Hide your heart</title>
<artist>Bonnie Tyler</artist>
<country>UK</country>
<quantity>10</quantity>
<price>9.90</price>
</cd>
<cd PurchaseDate="20000102">
<title>Greatest Hits</title>
<artist>Dolly Parton</artist>
<country>USA</country>
<quantity>15</quantity>
<price>9.90</price>
</cd>
<cd PurchaseDate="20000101">
<title>Still got the blues</title>
<artist>Gary Moore</artist>
<country>UK</country>
<quantity>5</quantity>
<price>10.20</price>
</cd>
<cd PurchaseDate="20000103">
<title>Eros</title>
<artist>Eros Ramazzotti</artist>
<country>EU</country>
<quantity>6</quantity>
<price>9.90</price>
</cd>
<cd PurchaseDate="20000103">
<title>One night only</title>
<artist>Bee Gees</artist>
<country>UK</country>
<quantity>16</quantity>
<price>10.90</price>
</cd>
<cd PurchaseDate="20000102">
<title>Sylvias Mother</title>
<artist>Dr.Hook</artist>
<country>UK</country>
<quantity>3</quantity>
<price>8.10</price>
</cd>
<cd PurchaseDate="20000101">
<title>Maggie May</title>
<artist>Rod Stewart</artist>
<country>UK</country>
<quantity>8</quantity>
<price>8.50</price>
</cd>
<cd PurchaseDate="20000103">
<title>Romanza</title>
<artist>Andrea Bocelli</artist>
<country>EU</country>
<quantity>30</quantity>
<price>10.80</price>
</cd>
</catalog>
..产生了(想要的?)结果:
<html>
<body>
<table border="1">
<tr bgcolor="#9acd32">
<td colspan="4">Country: EU</td>
</tr>
<tr>
<td>Purchase Date</td>
<td>Quantity</td>
<td>Unit Price</td>
<td>Total</td>
</tr>
<tr>
<td>20000103</td>
<td>6</td>
<td>9.90</td>
<td>59.4</td>
</tr>
<tr>
<td>20000103</td>
<td>30</td>
<td>10.80</td>
<td>324</td>
</tr>
<tr bgcolor="#9acd32">
<td colspan="4">Subtotal: 383.4</td>
</tr>
<tr bgcolor="#9acd32">
<td colspan="4">Country: UK</td>
</tr>
<tr>
<td>Purchase Date</td>
<td>Quantity</td>
<td>Unit Price</td>
<td>Total</td>
</tr>
<tr>
<td>20000101</td>
<td>10</td>
<td>9.90</td>
<td>99</td>
</tr>
<tr>
<td>20000101</td>
<td>5</td>
<td>10.20</td>
<td>51</td>
</tr>
<tr>
<td>20000101</td>
<td>8</td>
<td>8.50</td>
<td>68</td>
</tr>
<tr>
<td>20000102</td>
<td>3</td>
<td>8.10</td>
<td>24.3</td>
</tr>
<tr>
<td>20000103</td>
<td>16</td>
<td>10.90</td>
<td>174.4</td>
</tr>
<tr bgcolor="#9acd32">
<td colspan="4">Subtotal: 416.7</td>
</tr>
<tr bgcolor="#9acd32">
<td colspan="4">Country: USA</td>
</tr>
<tr>
<td>Purchase Date</td>
<td>Quantity</td>
<td>Unit Price</td>
<td>Total</td>
</tr>
<tr>
<td>20000101</td>
<td>20</td>
<td>10.90</td>
<td>218</td>
</tr>
<tr>
<td>20000102</td>
<td>15</td>
<td>9.90</td>
<td>148.5</td>
</tr>
<tr bgcolor="#9acd32">
<td colspan="4">Subtotal: 366.5</td>
</tr>
<tr bgcolor="#9acd32">
<td colspan="4">Total: 1166.6</td>
</tr>
</table>
</body>
</html>
...当呈现为HTML时,它看起来像这样:
此解决方案的秘诀是递归命名模板,该模板对每个<quantity>
和<price>
组合的产品进行求和。此模板用于计算每个国家/地区的小计,最后计算所有国家/地区的总和。特别感谢Dimitre Novatchev为这个宝石(Multiply 2 numbers and then sum)。