我已经解决了这个问题,但我想实现更好的代码。我试图确定发生非零金融事件的最后日期。请注意,为简洁起见,这是一个剥离和更改的XML,因此可以解释任何格式化的怪异。我使用的实际XML具有从1/1/2018到12/31/2029的更改金额,从4/1/2018到12/31/2029的所有内容总计为0.
<Products>
<Cost>
<Company name="A"/>
<Financials>
<Change amount="-10000">
<Date date="1/1/2018" dateindays="42734">
<Type name="open">
<Change>
<Change amount="4500">
<Date date="2/1/2018" dateindays="42765">
<Type name="debit">
</Change>
<Change amount="4500">
<Date date="3/1/2018" dateindays="42793">
<Type name="debit">
</Change>
<Change amount="4500">
<Date date="4/1/2018" dateindays="42824">
<Type name="debit">
</Change>
<Change amount="-2000">
<Date date="4/1/2018" dateindays="42824">
<Type name="debit">
<Change>
<Change amount="-2500">
<Date date="4/1/2018" dateindays="42824">
<Type name="debit">
</Financials>
</Cost>
</Products>
在上面的代码段中我想要3/1/2018的日期,因为4月1日的日期总计为0借记。
使用XSLT 2.0,我使用以下代码排除了4/1/2018的日期,但我还没有找到只返回3/1/2018日期的方法。我尝试过的每件事都已经将4/1/2018作为系列中的最后一个日期。
<xsl:for-each-group select="Products/Cost[Company/@name =
$Company]/Financials/Change[Type/@name = 'Debit']/Date" group-
by="@dateindays">
<xsl:sort select="@dateindays" data-type="number" order="descending"/>
<xsl:variable name="actDate" select="@dateindays"/>
<xsl:if test="sum(/Products/Cost[Company/@name =
$Company]/Financials/Change[Type/@name = 'Debit' and Date/@dateindays =
$actDate]/@amount) != 0">
<xsl:value-of select="@date"/>
</xsl:if>
</xsl:for-each-group>
正如我所说的,我做了一些黑客攻击(Excel中的隐藏单元格),但我真的想在代码中处理它,因为看起来这个日期可能会成为代码中后续过滤的一部分。
答案 0 :(得分:3)
我认为您可以使用当前组的总和进行检查,然后您需要在变量中输出这些元素,然后获取该变量值中的第一项:
<xsl:variable name="non-zero" as="element(Date)*">
<xsl:for-each-group select="Products/Cost[Company/@name = 'A']/Financials/Change[Type/@name = 'debit']" group-by="Date/@dateindays">
<xsl:sort select="current-grouping-key()" data-type="number" order="descending"/>
<xsl:variable name="actDate" select="@dateindays"/>
<xsl:if test="sum(current-group()/@amount) != 0">
<Date>{Date/@date}</Date>
</xsl:if>
</xsl:for-each-group>
</xsl:variable>
<xsl:value-of select="$non-zero[1]"/>
https://xsltfiddle.liberty-development.net/pPgCcoC
<Date>{Date/@date}</Date>
是XSLT 3,在XSLT 2中你需要<Date><xsl:value-of select="Date/@date"/></Date>
。
答案 1 :(得分:0)
这是与马丁相似的另一种选择。我喜欢马丁的更好(+1),但是因为我已经写好了,所以我会继续添加它。
XSLT 2.0
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="#all">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="company" select="'A'"/>
<xsl:key name="changes" match="Change" use="Date/@dateindays"/>
<xsl:template match="/">
<xsl:apply-templates select="Products/Cost[Company/@name = $company]/Financials"/>
</xsl:template>
<xsl:template match="Financials">
<xsl:variable name="non-zero-days" as="xs:float*">
<xsl:for-each-group select="Change" group-by="Date/@dateindays">
<xsl:if test="sum(current-group()/@amount) != 0">
<xsl:sequence select="data(Date/@dateindays)"/>
</xsl:if>
</xsl:for-each-group>
</xsl:variable>
<results>
<xsl:value-of select="key('changes',string(max($non-zero-days)))[1]/Date/@date"/>
</results>
</xsl:template>
</xsl:stylesheet>
<强>输出强>
<results>3/1/2018</results>
答案 2 :(得分:0)
我会采用两阶段方法:首先对数据进行分组,然后对组进行操作。
在第一阶段,你转换
<Change amount="4500">
<Date date="4/1/2018" dateindays="42824">
<Type name="debit">
</Change>
<Change amount="-2000">
<Date date="4/1/2018" dateindays="42824">
<Type name="debit">
</Change>
<Change amount="-2500">
<Date date="4/1/2018" dateindays="42824">
<Type name="debit">
</Change>
到
<Date date="4/1/2018" dateindays="42824">
<Change amount="4500">
<Type name="debit">
</Change>
<Change amount="-2000">
<Type name="debit">
</Change>
<Change amount="-2500">
<Type name="debit">
</Change>
</Date>
(这是xsl:for-each-group的一个简单使用)
在第二阶段,您应用过滤,例如Date[sum(Change/@amount)!=0)][last()]