从具有嵌套 if 的每个组中选取序列中的最后一个



我已经解决了这个问题,但我想实现一个更好的代码。我正在尝试确定发生非零金融事件的最后日期。请注意,为了简洁起见,这是一个剥离和更改的 XML,因此请原谅任何格式上的奇怪之处。我使用的实际 XML 的变化量从 2018 年 1 月 1 日到 2029 年 12 月 31 日,从 2018 年 4 月 1 日到 2029 年 12 月 31 日的所有内容总计为 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 月 2018 日的日期总计为 0 借方。

使用 XSLT 2.0,我使用以下代码排除了 2018 年 4 月 1 日的日期,但我还没有找到仅返回 2018 年 3 月 1 日日期的方法。我尝试过的每件事都返回了 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中的隐藏单元格(,但我真的想在代码中处理它,因为看起来这个日期可能需要作为以后代码过滤的一部分。

我认为您可以使用当前组的总和进行检查,然后您需要在变量中输出这些元素,然后在该变量值中获取第一项:

  <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(,但由于我已经写好了,所以我会继续添加它。

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>

工作小提琴:https://xsltfiddle.liberty-development.net/3Nqn5Yn/1

我会采用两阶段的方法:首先对数据进行分组,然后对组执行所需的操作。

在第一阶段,您进行转换

   <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()]

最新更新