【问题标题】:Grouping of consecutive days for different employees对不同员工的连续天数进行分组
【发布时间】:2021-02-16 21:37:37
【问题描述】:

我有一个 xml,其中同一员工在不同日期的不同条目如下:

<wd:Report_Data
    <wd:Report_Entry>
        <wd:workerGroup>
            <wd:staffID>111</wd:staffID>
        </wd:workerGroup>
        <wd:workerType>Staff</wd:workerType>
        <wd:requestType>Absence Request</wd:requestType>
        <wd:date>2020-08-21-07:00</wd:date>
    </wd:Report_Entry>
    <wd:Report_Entry>
        <wd:workerGroup>
            <wd:staffID>111</wd:staffID>
        </wd:workerGroup>
        <wd:workerType>Staff</wd:workerType>
        <wd:requestType>Absence Request</wd:requestType>
        <wd:date>2020-08-22-07:00</wd:date>
    </wd:Report_Entry>
    <wd:Report_Entry>
        <wd:workerGroup>
            <wd:staffID>222</wd:staffID>
        </wd:workerGroup>
        <wd:workerType>Staff</wd:workerType>
        <wd:requestType>Absence Request</wd:requestType>
        <wd:date>2020-08-23-07:00</wd:date>
    </wd:Report_Entry>
    <wd:Report_Entry>
        <wd:workerGroup>
            <wd:staffID>333</wd:staffID>
        </wd:workerGroup>
        <wd:workerType>Staff</wd:workerType>
        <wd:requestType>Absence Request</wd:requestType>
        <wd:date>2020-08-15-07:00</wd:date>
    </wd:Report_Entry>
    <wd:Report_Entry>
        <wd:workerGroup>
            <wd:staffID>333</wd:staffID>
        </wd:workerGroup>
        <wd:workerType>Staff</wd:workerType>
        <wd:requestType>Absence Request</wd:requestType>
        <wd:date>2020-08-16-07:00</wd:date>
    </wd:Report_Entry>
    <wd:Report_Entry>
        <wd:workerGroup>
            <wd:staffID>333</wd:staffID>
        </wd:workerGroup>
        <wd:workerType>Staff</wd:workerType>
        <wd:requestType>Absence Request</wd:requestType>
        <wd:date>2020-08-29-07:00</wd:date>
    </wd:Report_Entry>
</wd:Report_Data>

我想要一个输出,它将连续日期与开始日期和结束日期分组如下:

<wd:Report_Entry>
   <worker>
      <staffID>111</staffID>
      <start_date>2020-08-21-07:00</start_date>
      <end_date>2020-08-22-07:00</end_date>
   </worker>
   <worker>
      <staffID>222</staffID>
      <start_date>2020-08-23-07:00</start_date>
      <end_date>2020-08-23-07:00</end_date>
   </worker>
   <worker>
      <staffID>333</staffID>
      <start_date>2020-08-15-07:00</start_date>
      <end_date>2020-08-16-07:00</end_date>
   </worker>
   <worker>
      <staffID>333</staffID>
      <start_date>2020-08-29-07:00</start_date>
      <end_date>2020-08-29-07:00</end_date>
   </worker>
</wd:Report_Entry>

我曾尝试使用 group-starting-with,但它在分组时与人员 ID 无关。

<xsl:template match="/wd:Report_Data">
  
    <wd:Report_Entry>
              <xsl:for-each-group select="wd:Report_Entry" group-starting-with="*[not(xs:date(wd:date) = xs:date(preceding-sibling::*[1]/wd:date) + xs:dayTimeDuration('P1D'))] "> 
            <worker>
                <staffID>
                    <xsl:value-of select="wd:workerGroup/wd:staffID"/>
                </staffID>
                <start_date>
                    <xsl:value-of select="wd:date"/>
                </start_date>
                <end_date>
                    <xsl:value-of select="current-group()[last()]/wd:date"/>
                </end_date>
            </worker>
            </xsl:for-each-group>
        <!--   </xsl:for-each-group> --> 
    </wd:Report_Entry>
   
</xsl:template>

得到如下输出错误

<wd:Report_Entry>
   <worker>
      <staffID>111</staffID>
      <start_date>2020-08-21-07:00</start_date>
      <end_date>2020-08-23-07:00</end_date>
   </worker>
</wd:Report_Entry>

【问题讨论】:

  • 从单个示例中不清楚输入可以有哪些变化。在您的示例中,员工 111 的两个项目是相邻的,然后是其他员工的项目。而且时差正好是一天。实际输入是否具有相同的简单结构,即两个相邻元素的时差为 1 天?一个员工可以有两个以上的项目吗?
  • 是的@MartinHonnen。每位员工每天都会有 1 个单独的报告条目。例如如果员工要求休假 5 天(例如 20 日至 24 日),那么我们每天将有 5 个不同的 Report_Entry - 20 日、21 日、22 日、23 日、24 日。然后我们可以为不同的员工采用同样的方式。上面的代码是一个真实的输入,除了staffID

标签: xml xslt grouping xslt-2.0 xslt-grouping


【解决方案1】:

首先在员工 ID 上使用group-by 似乎就足够了,然后按日期对组进行排序,然后按相邻日期减去 position() * 1 天进行分组:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="3.0"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xpath-default-namespace="http://example.com/wd"
    exclude-result-prefixes="#all"
    expand-text="yes">
    
    <xsl:output method="xml" indent="yes"/>
    
    <xsl:template match="Report_Data">
        <root>
            <xsl:for-each-group select="Report_Entry" group-by="workerGroup/staffID">
                <xsl:for-each-group select="sort(current-group(), (), function($e) { $e/date })" group-adjacent="xs:date(date) - position() * xs:dayTimeDuration('P1D')">
                    <worker>
                        <staffID>
                            <xsl:value-of select="workerGroup/staffID"/>
                        </staffID>
                        <start_date>
                            <xsl:value-of select="date[1]"/>
                        </start_date>
                        <end_date>
                            <xsl:value-of select="current-group()[last()]/date"/>
                        </end_date>
                    </worker>
                </xsl:for-each-group>
            </xsl:for-each-group>
        </root>
    </xsl:template>
    
</xsl:stylesheet>

对于 XSLT 2 处理器,您可能需要在基于 xsl:perform-sort 的用户定义函数中实现排序:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="3.0"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:mf="http://example.com/mf"
    xpath-default-namespace="http://example.com/wd"
    exclude-result-prefixes="#all"
    expand-text="yes">
    
    <xsl:function name="mf:sort-by-date" as="element(Report_Entry)*">
        <xsl:param name="entries" as="element(Report_Entry)*"/>
        <xsl:perform-sort select="$entries">
            <xsl:sort select="date"/>
        </xsl:perform-sort>
    </xsl:function>
    
    <xsl:output method="xml" indent="yes"/>
    
    <xsl:template match="Report_Data">
        <root>
            <xsl:for-each-group select="Report_Entry" group-by="workerGroup/staffID">
                <xsl:for-each-group select="mf:sort-by-date(current-group())" group-adjacent="xs:date(date) - position() * xs:dayTimeDuration('P1D')">
                    <worker>
                        <staffID>
                            <xsl:value-of select="workerGroup/staffID"/>
                        </staffID>
                        <start_date>
                            <xsl:value-of select="date[1]"/>
                        </start_date>
                        <end_date>
                            <xsl:value-of select="current-group()[last()]/date"/>
                        </end_date>
                    </worker>
                </xsl:for-each-group>
            </xsl:for-each-group>
        </root>
    </xsl:template>
    
</xsl:stylesheet>

当然,只有当输入没有按员工ID和日期排序时才需要排序,否则呈现的分组就足够了。

【讨论】:

  • 感谢@martin,但这样它也会将非连续的日子分组。如果员工在 20 日到 22 日申请休假,然后在 25 日到 28 日再次申请休假,那么我应该得到 2 组(第 1 组:20-22;第 2 组:25-28)。这就是为什么我尝试使用&lt;xsl:for-each-group select="wd:Report_Entry" group-starting-with="*[not(xs:date(wd:date) = xs:date(preceding-sibling::*[1]/wd:date) + xs:dayTimeDuration('P1D'))] "&gt;您的代码将只提供 1 组,开始日期为 20 日,结束日期为 28 日
  • 只有员工ID相同且日期连续时才应进行分组
  • @AdityaGG,您能否编辑您的问题并向我们展示员工将生产多个组的情况的输入和输出示例。我仍然不知道是否为所有项目形成了组,这些项目相隔一天或任何间隔。
  • @AdityaGG,看看编辑是否更接近你想要的。
  • 我在上面编辑了我的输入和预期输出(为另一个员工 333 添加了一个场景)。 333 应该有 2 组 - 从 15 日到 16 日,因为它们是连续的天数,另一组是 29 日。第一种情况是 2 名员工 - 111 名(第 21 名和第 22 名)和 222 名(第 23 名)。这里所有日期都是连续的,但由于人员 ID 不同,我想要 2 组 - 111(开始日期 21 日;结束日期 22 日)和 222(开始日期 23 日;结束日期 23 日)各一组
猜你喜欢
  • 2023-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-13
  • 2021-12-22
相关资源
最近更新 更多