想知道这是否可以使用XSLT ...
有我正在处理的数据。我们看到一组行(我在这里只显示一行)和字段。字段代表一种销售方式。例如,boucherie
。每种类型都有每日销售和一些销售。
<?xml version="1.0"?>
<snap-report>
<row>
<field type="boucherie" group="sales" class="sales">
<day date="20140801"><amount>123.22</amount><count>3</count></day>
<day date="20140802"><amount>23.29</amount><count>5</count></day>
<day date="20140803"><amount>32.24</amount><count>2</count></day>
<day date="20140804"><amount>53.72</amount><count>10</count></day>
<day date="20140805"><amount>57.12</amount><count>7</count></day>
<day date="20140806"><amount>133.46</amount><count>12</count></day>
<day date="20140807"><amount>253.00</amount><count>20</count></day>
</field>
<field type="legumes" group="sales" class="sales">
<day date="20140801"><amount>23.22</amount><count>3</count></day>
<day date="20140802"><amount>55.09</amount><count>5</count></day>
<day date="20140803"><amount>132.24</amount><count>2</count></day>
<day date="20140804"><amount>5.70</amount><count>1</count></day>
<day date="20140805"><amount>205.07</amount><count>18</count></day>
<day date="20140806"><amount>50.32</amount><count>2</count></day>
<day date="20140807"><amount>93.72</amount><count>11</count></day>
</field>
<field type="dessert" group="sales" class="sales">
<day date="20140801"><amount>145.23</amount><count>17</count></day>
<day date="20140802"><amount>3.29</amount><count>1</count></day>
<day date="20140803"><amount>302.04</amount><count>23</count></day>
<day date="20140804"><amount>59.11</amount><count>11</count></day>
<day date="20140805"><amount>35.72</amount><count>7</count></day>
<day date="20140806"><amount>50.82</amount><count>3</count></day>
<day date="20140807"><amount>67.02</amount><count>5</count></day>
</field>
</row>
</snap-report>
我们希望计算一个数字,表示数据中每天可用的平均销售额。假设所有字段标记都与彼此具有相同的日期(我相信该XML的来源。)这很容易,我得到了几个模板如下:
<?xml version="1.0"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
xmlns:snap="snap:snap">
<!-- some special variables to define the theme -->
<!-- xsl:variable name="layout-name">finball</xsl:variable>
<xsl:variable name="layout-area">report-table</xsl:variable>
<xsl:variable name="layout-modified">2014-08-02 16:45:29</xsl:variable -->
<xsl:template name="cell">
<xsl:param name="date"/>
<xsl:variable name="sales_total_amount" select="sum(../../field[@group='sales']/day[@date=$date]/amount)"/>
<xsl:variable name="sales_total_count" select="sum(../../field[@group='sales']/day[@date=$date]/count)"/>
<xsl:text>$</xsl:text><xsl:value-of select="$sales_total_amount div $sales_total_count"/>
</xsl:template>
<xsl:template match="row">
<tr>
<td>Average Income</td>
<!-- use one list of days, we only need that from the first field
we expect the lists to always be sorted so not sort in XSLT -->
<xsl:for-each select="field[1]/day">
<td>
<!-- sum up all the fields here -->
<xsl:call-template name="cell">
<xsl:with-param name="date" select="@date"/>
</xsl:call-template>
</td>
</xsl:for-each>
<!-- this cell is the one I have a problem with... -->
<td class="average">
<xsl:variable name="sales_total_amount" select="sum(field[@group='sales']/day/amount)"/>
<xsl:variable name="sales_total_count" select="sum(field[@group='sales']/day/count)"/>
<xsl:text>$</xsl:text><xsl:value-of select="$sales_total_amount div $sales_total_count"/>
</td>
</tr>
</xsl:template>
<xsl:template match="snap-report">
<table class="report">
<xsl:apply-templates select="row"/>
</table>
</xsl:template>
</xsl:stylesheet>
我们看到数学是这样的(伪代码):
sum(.sales) / sum(.count)
当天的销售总额,来自每个字段,除以销售的商品总数。输出符合该部分的预期。
但是,行中的最后一个单元格表示先前单元格的平均值。所以在伪代码中,它将类似于:
sum(td) / count(td)
前一个单元格中的数字之和除以单元格数。 (事实上,我们必须考虑一个空条目的特殊情况,设置为零,但我想我能够及时处理。)
但是,我使用的当前数学计算错误的平均值:
sale[1] + sale[2] + sale[3] ...
--------------------------------
cnt[1] + cnt[2] + cnt[3] ...
因为预期的平均值是:
td[1] td[2] td[3]
------ + ------ + ------ + ...
cnt[1] cnt[2] cnt[3]
-------------------------------
n
哪里&#39; n&#39;是该行中有效天数。
那些数字(td [1] / cnt [1])是我们已经为该表中的前几个单元格正确计算的数字。不幸的是,就我所知,当我们到达最后一个单元格时,这个总数已经丢失到了XSLT ......
有我当前的输出和
<table class="report">
<tr>
<td>Average Income</td>
<td>$12.681304347826085</td>
<td>$7.424545454545455</td>
<td>$17.27851851851852</td>
<td>$5.387727272727273</td>
<td>$9.309687499999999</td>
<td>$13.799999999999999</td>
<td>$11.492777777777778</td>
<td class="average">$11.337142857142856</td>
</tr>
</table>
最后一个条目,$ 11.3371 ......错了。正确的数字应为$ 11.0535087。根据我使用的数字,差异会有很大差异,但无论如何你都可以看到数学不正确,如前所示。
问题是,是否有一种简单的方法来计算XSLT 2.0中的正确平均值?
答案 0 :(得分:1)
使用XSLT 2.0,您可以轻松地将计算结果存储在序列或临时树中:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:output method="html" indent="yes"/>
<xsl:template match="row">
<tr>
<td>Average Income</td>
<!-- use one list of days, we only need that from the first field
we expect the lists to always be sorted so not sort in XSLT -->
<xsl:variable name="sales-by-day">
<xsl:for-each-group select="field[@group = 'sales']/day" group-by="@date">
<sales day="{current-grouping-key()}">
<amount><xsl:value-of select="sum(current-group()/amount)"/></amount>
<count><xsl:value-of select="sum(current-group()/count)"/></count>
</sales>
</xsl:for-each-group>
</xsl:variable>
<xsl:for-each select="$sales-by-day/sales">
<td>
<xsl:text>$</xsl:text><xsl:value-of select="amount div count"/>
</td>
</xsl:for-each>
<!-- this cell is the one I have a problem with... -->
<td class="average">
<xsl:text>$</xsl:text><xsl:value-of select="sum($sales-by-day/sales/(amount div count)) div count(field[@group = 'sales'][1]/day)"/>
</td>
</tr>
</xsl:template>
<xsl:template match="snap-report">
<table class="report">
<xsl:apply-templates select="row"/>
</table>
</xsl:template>
</xsl:stylesheet>
我认为以上内容可以缩短为
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:output method="html" indent="yes"/>
<xsl:template match="row">
<tr>
<td>Average Income</td>
<!-- use one list of days, we only need that from the first field
we expect the lists to always be sorted so not sort in XSLT -->
<xsl:variable name="sales-by-day">
<xsl:for-each-group select="field[@group = 'sales']/day" group-by="@date">
<sales day="{current-grouping-key()}">
<xsl:value-of select="sum(current-group()/amount) div sum(current-group()/count)"/>
</sales>
</xsl:for-each-group>
</xsl:variable>
<xsl:for-each select="$sales-by-day/sales">
<td>
<xsl:text>$</xsl:text><xsl:value-of select="."/>
</td>
</xsl:for-each>
<!-- this cell is the one I have a problem with... -->
<td class="average">
<xsl:text>$</xsl:text><xsl:value-of select="sum($sales-by-day/sales) div count($sales-by-day/sales)"/>
</td>
</tr>
</xsl:template>
<xsl:template match="snap-report">
<table class="report">
<xsl:apply-templates select="row"/>
</table>
</xsl:template>
</xsl:stylesheet>