请帮助我使用XSLT中的数学。我需要总计具有相同unit_id的增值税字段。
输入XML:
<Root>
<RowSet>
<unit_id>1<unit_id>
<price>100<unit_id>
<VAT>2<VAT>
</RowSet>
<RowSet>
<unit_id>1<unit_id>
<price>200<unit_id>
<VAT>3<VAT>
</RowSet>
<RowSet>
<unit_id>2<unit_id>
<price>300<unit_id>
<VAT>4<VAT>
</RowSet>
</Root>
预期输出必须是这样的:
<Root>
<Output>
<unit_id>1<unit_id>
<total>800<total> <?-(100*2+200*3)-?>
</Output>
<Output>
<unit_id>2<unit_id>
<total>1200<total> <?-(300*4)-?>
</Output>
</Root>
我在仪式周期中尝试了总和(价格*增值税),但没有帮助。
我试图使用以下方式:
<Root>
<xsl:variable name="ID">
<xsl:value-of select="unit_id"/>
</xsl:variable>
<xsl:for-each select="/Root/RowSet[unit_id = $ID]">
<Output>
<xsl:if test="position() = count (/Root/RowSet[unit_id = $ID])">
<total>
<xsl:value-of select="sum(/Root/RowSet[unit_id = $ID]/price * /Root/RowSet[unit_id = $ID]/VAT)"/>
</total>
</xsl:if>
</Output>
</Root>
错误的输出是:
<Root>
<Output>
<unit_id>1<unit_id>
<total>200<total> <?-(100*2)-?>
</Output>
<Output>
<unit_id>2<unit_id>
<total>1200<total> <?-(300*4)-?>
</Output>
</Root>
运行总计是XSLT中的常见问题。递归是解决该问题的方法。(这不是XSLT唯一的 - 任何没有可变变量的语言可以正常工作。)
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<Root>
<xsl:apply-templates select="Root/RowSet" />
</Root>
</xsl:template>
<xsl:template match="RowSet">
<!-- only do work for the *first* RowSet with any particular ID -->
<xsl:if test="not(preceding-sibling::RowSet/unit_id = current()/unit_id)">
<Output>
<xsl:copy-of select="unit_id" />
<total>
<xsl:call-template name="running-total">
<xsl:with-param name="values" select="/Root/RowSet[
unit_id = current()/unit_id
]" />
</xsl:call-template>
</total>
</Output>
</xsl:if>
</xsl:template>
<xsl:template name="running-total">
<xsl:param name="values" />
<xsl:choose>
<xsl:when test="count($values)">
<xsl:variable name="curr" select="$values[1]" />
<xsl:variable name="rest" select="$values[position() > 1]" />
<!-- recursive step: calculate the total of all remaining values -->
<xsl:variable name="subtotal">
<xsl:call-template name="running-total">
<xsl:with-param name="values" select="$rest" />
</xsl:call-template>
</xsl:variable>
<xsl:value-of select="$subtotal + $curr/price * $curr/VAT" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="0" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
请参阅http://www.xmlplayground.com/nf7d2o
笔记
<xsl:if test="not(preceding-sibling::RowSet/unit_id = current()/unit_id)">
是分组数据的一种方式。这样做的更高级的方法称为穆恩式分组,但为了这个答案,我不想进入。
running-total
模板在JavaScript中看起来像这样:
function runningTotal(values) {
if (values.length) {
var curr = values.pop(); // pop() shortens values array by one
var subtotal = runningTotal(values); // recurses over remaining values
return subtotal + curr.price * curr.VAT;
} else {
return 0;
}
}
这是一个非恢复的,两个 - 通过解决方案:
<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="kRSByUId" match="RowSet" use="unit_id"/>
<xsl:variable name="vrtfPass1"><xsl:apply-templates/></xsl:variable>
<xsl:template match="node()|@*" name="identity">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:apply-templates mode="pass2" select="ext:node-set($vrtfPass1)/*"/>
</xsl:template>
<xsl:template mode="pass2" match="/*">
<Root>
<xsl:apply-templates mode="pass2" select=
"RowSet[generate-id()
=
generate-id(key('kRSByUId', unit_id)[1])]"/>
</Root>
</xsl:template>
<xsl:template mode="pass2" match="RowSet">
<RowSet>
<xsl:copy-of select="unit_id"/>
<total>
<xsl:value-of select="sum(key('kRSByUId', unit_id)/subTotal)"/>
</total>
</RowSet>
</xsl:template>
<xsl:template match="RowSet/price">
<subTotal><xsl:value-of select=". * ../VAT"/></subTotal>
</xsl:template>
<xsl:template match="VAT"/>
</xsl:stylesheet>
将此转换应用于提供的XML文档(严重的畸形纠正):
<Root>
<RowSet>
<unit_id>1</unit_id>
<price>100</price>
<VAT>2</VAT>
</RowSet>
<RowSet>
<unit_id>1</unit_id>
<price>200</price>
<VAT>3</VAT>
</RowSet>
<RowSet>
<unit_id>2</unit_id>
<price>300</price>
<VAT>4</VAT>
</RowSet>
</Root>
想要的,正确的结果:
<Root>
<RowSet>
<unit_id>1</unit_id>
<total>800</total>
</RowSet>
<RowSet>
<unit_id>2</unit_id>
<total>1200</total>
</RowSet>
</Root>
说明:
- 在第一个通过中,我们将源XML文档转换为:
<Root>
<RowSet>
<unit_id>1</unit_id>
<subTotal>200</subTotal>
</RowSet>
<RowSet>
<unit_id>1</unit_id>
<subTotal>600</subTotal>
</RowSet>
<RowSet>
<unit_id>2</unit_id>
<subTotal>1200</subTotal>
</RowSet>
</Root>
.2。在第二次通过中,我们执行经典的Muenchian分组,并在每个组中总结subTotal
儿童并产生total
元素,其文本节点子是如此计算的总和。