the grouping of consecutive days for different employees

It seems sufficient to use group-by on the staff id first and then sort the group on the date to then group by adjacent dates minus position() * 1 day:

<?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>

For an XSLT 2 processor you might need to implement the sorting in a user-defined function based on 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>

Of course the sorting is only necessary if the input is not sorted by staff id and date, otherwise the presented grouping should suffice.

CLICK HERE to find out more related problems solutions.

Leave a Comment

Your email address will not be published.

Scroll to Top