我有以下输入xml:
<Input>
<Incomes>
<Income>
<Year>2016</Year>
<Amount>10000</Amount>
</Income>
<Income>
<Year>2017</Year>
<Amount>20000</Amount>
</Income>
<Income>
<Year>2018</Year>
<Amount>30000</Amount>
</Income>
</Incomes>
<Expenses>
<Expense>
<Year>2016</Year>
<Amount>2000</Amount>
</Expense>
<Expense>
<Year>2017</Year>
<Amount>5000</Amount>
</Expense>
<Expense>
<Year>2018</Year>
<Amount>10000</Amount>
</Expense>
</Expenses>
</Input>
我想使用xslt将其转换为以下输出xml:
<Output>
<Savings>
<Saving>
<Year>2016</Year>
<Amount>8000</Amount>
<!-- Income of 2016 - Expense of 2016 -->
</Saving>
<Saving>
<Year>2017</Year>
<Amount>15000</Amount>
<!-- Income of 2017 - Expense of 2017 -->
</Saving>
<Saving>
<Year>2018</Year>
<Amount>20000</Amount>
</Saving>
</Savings>
<CumulativeSavings>
<CumulativeSaving>
<Year>2016</Year>
<Amount>8000</Amount><!-- Income of 2016 - Expense of 2016 -->
</CumulativeSaving>
<CumulativeSaving>
<Year>2017</Year>
<Amount>23000</Amount><!-- Income of 2017 - Expense of 2017 + Cumulative Saving of 2016 -->
</CumulativeSaving>
<CumulativeSaving>
<Year>2018</Year>
<Amount>43000</Amount><!-- Income of 2018 - Expense of 2018 + Cumulative Saving of 2017 -->
</CumulativeSaving>
</CumulativeSavings>
</Output>
我正在使用<xsl:for-each select="">
遍历所有收入,支出,但是我不确定如何执行收入-支出计算。另外,我需要累积保存,如输出xml中所示。
答案 0 :(得分:2)
这是一个更通用的解决方案,即使在Income
和Expense
元素数量不同的情况下也可以使用-Income
在同一年没有Expense
匹配,Expense
,在同一年内无法与Income
匹配,甚至在同一年甚至没有匹配的多个Income
和/或Expense
元素。
它还使用 FXSL-2 及其函数f:scanl()
,该函数计算运行总计(一个人可以阅读有关FXSL here和here的更多信息)。
因此,仅用以下一行代码就可以根据已经计算出的节省量来计算运行总额:
<xsl:variable name="vCumulatives" select="f:scanl1(f:add(), $vSavingsResult/*/Amount)"/>
这是完整的转换(将两个<xsl:import>
指令中的@href值替换为您所引用的FXLS样式表的本地路径):
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:f="http://fxsl.sf.net/"
exclude-result-prefixes="xs f">
<xsl:import href="file:///C:/CVS-DDN/fxsl-xslt2/f/func-scanl.xsl"/>
<xsl:import href="file:///C:/CVS-DDN/fxsl-xslt2/f/func-Operators.xsl"/>
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:key name="kIncomeByYear" match="Income" use="Year"/>
<xsl:key name="kExpenseByYear" match="Expense" use="Year"/>
<xsl:template match="node()|@*" mode="#default savings cumulative">
<xsl:copy>
<xsl:apply-templates select="node()|@*" mode="#current"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*[Incomes/Income | Expenses/Expense]">
<xsl:variable name="vSavingsResult">
<xsl:apply-templates mode="savings" select=
"*/Income[generate-id() = generate-id(key('kIncomeByYear', Year)[1])]
| */Expense[not(key('kIncomeByYear', Year))
and generate-id() = generate-id(key('kExpenseByYear', Year)[1])]">
<xsl:sort select="Year"/>
</xsl:apply-templates>
</xsl:variable>
<xsl:variable name="vCumulatives" select="f:scanl1(f:add(), $vSavingsResult/*/Amount)"/>
<Output>
<Savings>
<xsl:sequence select="$vSavingsResult/*"/>
</Savings>
<CumulativeSavings>
<xsl:apply-templates select="$vSavingsResult/*" mode="cumulative">
<xsl:with-param name="pCumulatives" select="$vCumulatives" tunnel="yes"/>
</xsl:apply-templates>
</CumulativeSavings>
</Output>
</xsl:template>
<xsl:template match="Income | Expense" mode="savings">
<Saving>
<xsl:apply-templates mode="#current"/>
</Saving>
</xsl:template>
<xsl:template match="Amount" mode="savings">
<Amount>
<xsl:value-of select=
"sum(key('kIncomeByYear', ../Year)/Amount)
- sum(key('kExpenseByYear', ../Year)/Amount)"/>
</Amount>
</xsl:template>
<xsl:template match="Saving" mode="cumulative">
<CumulativeSaving><xsl:apply-templates mode="#current"/></CumulativeSaving>
</xsl:template>
<xsl:template match="Amount" mode="cumulative">
<xsl:param name="pCumulatives" tunnel="yes"/>
<xsl:variable name="vSavingsPos" select="count(../preceding-sibling::*) +1"/>
<Amount><xsl:value-of select="$pCumulatives[$vSavingsPos]"/></Amount>
</xsl:template>
</xsl:stylesheet>
此转换应用于提供的XML文档时:
<Input>
<Incomes>
<Income>
<Year>2016</Year>
<Amount>10000</Amount>
</Income>
<Income>
<Year>2017</Year>
<Amount>20000</Amount>
</Income>
<Income>
<Year>2018</Year>
<Amount>30000</Amount>
</Income>
</Incomes>
<Expenses>
<Expense>
<Year>2016</Year>
<Amount>2000</Amount>
</Expense>
<Expense>
<Year>2017</Year>
<Amount>5000</Amount>
</Expense>
<Expense>
<Year>2018</Year>
<Amount>10000</Amount>
</Expense>
</Expenses>
</Input>
产生想要的正确结果:
<Output>
<Savings>
<Saving>
<Year>2016</Year>
<Amount>8000</Amount>
</Saving>
<Saving>
<Year>2017</Year>
<Amount>15000</Amount>
</Saving>
<Saving>
<Year>2018</Year>
<Amount>20000</Amount>
</Saving>
</Savings>
<CumulativeSavings>
<CumulativeSaving>
<Year>2016</Year>
<Amount>8000</Amount>
</CumulativeSaving>
<CumulativeSaving>
<Year>2017</Year>
<Amount>23000</Amount>
</CumulativeSaving>
<CumulativeSaving>
<Year>2018</Year>
<Amount>43000</Amount>
</CumulativeSaving>
</CumulativeSavings>
</Output>
这里是一个XML文档,其中包含不匹配的Income
元素(2014年),和不匹配的Expense
元素(2015年) :
<Input>
<Incomes>
<Income>
<Year>2014</Year>
<Amount>500</Amount>
</Income>
<Income>
<Year>2016</Year>
<Amount>10000</Amount>
</Income>
<Income>
<Year>2017</Year>
<Amount>20000</Amount>
</Income>
<Income>
<Year>2018</Year>
<Amount>30000</Amount>
</Income>
</Incomes>
<Expenses>
<Expense>
<Year>2015</Year>
<Amount>1000</Amount>
</Expense>
<Expense>
<Year>2016</Year>
<Amount>2000</Amount>
</Expense>
<Expense>
<Year>2017</Year>
<Amount>5000</Amount>
</Expense>
<Expense>
<Year>2018</Year>
<Amount>10000</Amount>
</Expense>
</Expenses>
</Input>
对其应用与上面相同的转换会产生正确的结果:
<Output>
<Savings>
<Saving>
<Year>2014</Year>
<Amount>500</Amount>
</Saving>
<Saving>
<Year>2015</Year>
<Amount>-1000</Amount>
</Saving>
<Saving>
<Year>2016</Year>
<Amount>8000</Amount>
</Saving>
<Saving>
<Year>2017</Year>
<Amount>15000</Amount>
</Saving>
<Saving>
<Year>2018</Year>
<Amount>20000</Amount>
</Saving>
</Savings>
<CumulativeSavings>
<CumulativeSaving>
<Year>2014</Year>
<Amount>500</Amount>
</CumulativeSaving>
<CumulativeSaving>
<Year>2015</Year>
<Amount>-500</Amount>
</CumulativeSaving>
<CumulativeSaving>
<Year>2016</Year>
<Amount>7500</Amount>
</CumulativeSaving>
<CumulativeSaving>
<Year>2017</Year>
<Amount>22500</Amount>
</CumulativeSaving>
<CumulativeSaving>
<Year>2018</Year>
<Amount>42500</Amount>
</CumulativeSaving>
</CumulativeSavings>
</Output>
最后,下面的XML文档除了不匹配的Income
和Expense
元素之外,每年还包含多个Income
和Expense
元素:< / p>
<Input>
<Incomes>
<Income>
<Year>2014</Year>
<Amount>100</Amount>
</Income>
<Income>
<Year>2014</Year>
<Amount>400</Amount>
</Income>
<Income>
<Year>2016</Year>
<Amount>10000</Amount>
</Income>
<Income>
<Year>2017</Year>
<Amount>20000</Amount>
</Income>
<Income>
<Year>2018</Year>
<Amount>30000</Amount>
</Income>
</Incomes>
<Expenses>
<Expense>
<Year>2015</Year>
<Amount>500</Amount>
</Expense>
<Expense>
<Year>2015</Year>
<Amount>500</Amount>
</Expense>
<Expense>
<Year>2016</Year>
<Amount>2000</Amount>
</Expense>
<Expense>
<Year>2017</Year>
<Amount>5000</Amount>
</Expense>
<Expense>
<Year>2018</Year>
<Amount>10000</Amount>
</Expense>
</Expenses>
</Input>
再次对该XML文档应用相同的转换会产生正确的结果:
<Output>
<Savings>
<Saving>
<Year>2014</Year>
<Amount>500</Amount>
</Saving>
<Saving>
<Year>2015</Year>
<Amount>-1000</Amount>
</Saving>
<Saving>
<Year>2016</Year>
<Amount>8000</Amount>
</Saving>
<Saving>
<Year>2017</Year>
<Amount>15000</Amount>
</Saving>
<Saving>
<Year>2018</Year>
<Amount>20000</Amount>
</Saving>
</Savings>
<CumulativeSavings>
<CumulativeSaving>
<Year>2014</Year>
<Amount>500</Amount>
</CumulativeSaving>
<CumulativeSaving>
<Year>2015</Year>
<Amount>-500</Amount>
</CumulativeSaving>
<CumulativeSaving>
<Year>2016</Year>
<Amount>7500</Amount>
</CumulativeSaving>
<CumulativeSaving>
<Year>2017</Year>
<Amount>22500</Amount>
</CumulativeSaving>
<CumulativeSaving>
<Year>2018</Year>
<Amount>42500</Amount>
</CumulativeSaving>
</CumulativeSavings>
</Output>
答案 1 :(得分:1)
考虑使用键查找费用项目
<xsl:key name="expenses" match="Expense" use="Year" />
然后,对于给定的Income
元素,您可以像这样获得量
<xsl:variable name="currentAmount" select="Amount - key('expenses', Year)/Amount" />
就获取累计总数而言,您可以使用递归模板一次获取Income
元素,并使用参数将当前值传递给下一个调用,因此,您可以输出Saving
和CumulativeSaving
元素。如果将此结果存储在变量中,则可以分别输出它们。
尝试使用此XSLT:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:key name="expenses" match="Expense" use="Year" />
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<xsl:variable name="calcs">
<xsl:apply-templates select="(//Income)[1]" />
</xsl:variable>
<Output>
<Savings>
<xsl:copy-of select="$calcs/Saving" />
</Savings>
<CumulativeSavings>
<xsl:copy-of select="$calcs/CumulativeSaving" />
</CumulativeSavings>
</Output>
</xsl:template>
<xsl:template match="Income">
<xsl:param name="previousAmount" select="0" />
<xsl:variable name="currentAmount" select="Amount - key('expenses', Year)/Amount" />
<xsl:variable name="newAmount" select="$currentAmount + $previousAmount" />
<Saving>
<xsl:copy-of select="Year" />
<Amount>
<xsl:value-of select="$currentAmount" />
</Amount>
</Saving>
<CumulativeSaving>
<xsl:copy-of select="Year" />
<Amount>
<xsl:value-of select="$newAmount" />
</Amount>
</CumulativeSaving>
<xsl:apply-templates select="following-sibling::Income[1]">
<xsl:with-param name="previousAmount" select="$newAmount" />
</xsl:apply-templates>
</xsl:template>
</xsl:stylesheet>
请注意,在XSLT 3.0中,您可以使用xsl:iterate
代替递归模板。参见http://xsltfiddle.liberty-development.net/pPzifqk)