xslt中相同类型的连续日期时间总计

时间:2018-02-22 01:12:26

标签: xslt xslt-2.0 xslt-grouping

我要求将相同类型的相应日期时间打印成一行,总时间为每次关闭行的单位总和,以及具有最早时间的最开始日期的开始日期和行结束日期是基于下面的XML的行开始日期的最新时间。

- XML -

<?xml version='1.0' encoding='UTF-8'?>
<Data>
    <Worker>
        <Worker_ID>12</Worker_ID>
        <Time_Off>
            <Type>Compassionate Leave</Type>
            <Date>2018-02-09-08:00</Date>
            <Units>1</Units>
        </Time_Off>
        <Time_Off>
            <Type>Compassionate Leave</Type>
            <Date>2018-02-08-08:00</Date>
            <Units>1</Units>
        </Time_Off>
        <Time_Off>
            <Type>Compassionate Leave</Type>
            <Date>2018-02-02-08:00</Date>
            <Units>1</Units>
        </Time_Off>
        <Time_Off>
            <Type>Compassionate Leave</Type>
            <Date>2018-02-01-08:00</Date>
            <Units>1</Units>
        </Time_Off>
        <Time_Off>
            <Type>Statutory Holiday</Type>
            <Date>2018-02-07-08:00</Date>
            <Units>1</Units>
        </Time_Off>
        <Time_Off>
            <Type>Statutory Holiday</Type>
            <Date>2018-02-06-08:00</Date>
            <Units>1</Units>
        </Time_Off>
    </Worker>
    <Worker>
        <Worker_ID>09</Worker_ID>
        <Time_Off>
            <Type>Sick Leave</Type>
            <Date>2018-02-10-08:00</Date>
            <Units>1</Units>
        </Time_Off>
    </Worker>
    <Worker>
        <Worker_ID>13</Worker_ID>
        <Time_Off>
            <Type>Vacation</Type>
            <Date>2018-02-11-08:00</Date>
            <Units>1</Units>
        </Time_Off>
        <Time_Off>
            <Type>Vacation</Type>
            <Date>2018-01-10-08:00</Date>
            <Units>1</Units>
        </Time_Off>
    </Worker>
</Data>

- 期望输出 -

    EmployeeID,TimeOff Type,TimeOff Start Date,TimeOff End Date,Total Units 
    12,Compassionate Leave,2018-02-08,2018-02-09,2
    12,Compassionate Leave,2018-02-01,2018-02-02,2
    12,Statutory Holiday,2018-02-06,2018-02-07,2
    09,Sick Leave,2018-02-10,2018-02-10,1
    13,Vacation,2018-02-11,2018-02-11,1
    13,Vacation,2018-01-10,2018-01-10,1

1 个答案:

答案 0 :(得分:0)

类似的问题How to group consecutive dates in XSLT?对于解决它有一些建议,无论是使用XSLT还是使用XQuery。

https://xqueryfiddle.liberty-development.net/pPgCcoj/1尝试使用XQuery 3中的window子句来解决您的问题:

declare function local:date($input as xs:string) as xs:date {
    xs:date(substring($input, 1, 10))
};


string-join((
    'EmployeeID,TimeOff Type,TimeOff Start Date,TimeOff End Date,Total Units',
for $worker in Data/Worker
for $time-off in $worker/Time_Off
group by $type := data($time-off/Type)
return
    let $times := for $time in $time-off
                  order by local:date($time/Date)
                  return $time
    return 
        for tumbling window $line in $times
        start $s when true()
        end $e next $n when empty($n) or local:date($n/Date) - local:date($e/Date) ne xs:dayTimeDuration('P1D')
        return string-join(
            ($worker/Worker_ID, $type, local:date($s/Date), local:date($e/Date), sum($line/Units)), ',')), '&#10;')

使用XSLT,您可以使用

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:mf="http://example.com/mf"
    exclude-result-prefixes="xs mf"
    version="3.0">

  <xsl:output method="text"/>
  <xsl:strip-space elements="*"/>

  <xsl:function name="mf:date" as="xs:date">
      <xsl:param name="input" as="xs:string"/>
      <xsl:sequence select="xs:date(substring($input, 1, 10))"/>
  </xsl:function>

  <xsl:function name="mf:line" as="xs:string">
      <xsl:param name="group" as="element(Time_Off)*"/>
      <xsl:value-of 
        select="$group[1]/../Worker_ID, 
                $group[1]/Type, 
                mf:date($group[1]/Date),
                mf:date($group[last()]/Date),
                sum($group/Units)"
                separator=","/>      
  </xsl:function>

  <xsl:template match="Worker">
      <xsl:for-each-group select="Time_Off" group-by="Type">
          <xsl:variable name="sorted-times" as="element(Time_Off)*">
              <xsl:perform-sort select="current-group()">
                  <xsl:sort select="mf:date(Date)"/>
              </xsl:perform-sort>
          </xsl:variable>
          <xsl:for-each-group select="$sorted-times" group-by="mf:date(Date) - xs:dayTimeDuration('P1D') * position()">
              <xsl:value-of select="mf:line(current-group()) || '&#10;'"/>
          </xsl:for-each-group>
      </xsl:for-each-group>
  </xsl:template>

</xsl:stylesheet>

在线https://xsltfiddle.liberty-development.net/pPgCcov/1。对于XSLT 2处理器,您需要使用<xsl:value-of select="concat(mf:line(current-group()), '&#10;')"/>而不是<xsl:value-of select="mf:line(current-group()) || '&#10;'"/>