Основной подход - простая составная группировка по трем ключевым значениям, только ночная смена усложняет ситуацию, так как вам нужно сгруппировать две разные даты, а также изменить выражения, чтобы найти время:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
expand-text="yes"
exclude-result-prefixes="#all"
version="3.0">
<xsl:mode on-no-match="shallow-copy"/>
<xsl:output method="html" indent="yes" html-version="5"/>
<xsl:template match="Data">
<table>
<thead>
<tr>
<th>Date</th>
<th>In-Time</th>
<th>Out-Time</th>
<th>EmpId</th>
<th>Shift</th>
</tr>
</thead>
<xsl:for-each-group select="Employees" composite="yes"
group-by="Empid,
if (Shift != '1C')
then
xs:date(Date)
else if (xs:time(Time) lt xs:time('08:00:00'))
then
xs:date(Date) - xs:dayTimeDuration('P1D')
else
xs:date(Date),
Shift">
<tbody>
<tr>
<td>{current-grouping-key()[2]}</td>
<td>{if (Shift != '1C')
then min(current-group()[InOut = 'In']/xs:time(Time))
else
min(current-group()[xs:date(Date) = current-grouping-key()[2]][InOut = 'In']/xs:time(Time))
}</td>
<td>{if (Shift != '1C')
then
max(current-group()[InOut = 'Out']/xs:time(Time))
else
max(current-group()[xs:date(Date) > current-grouping-key()[2]][InOut = 'Out']/xs:time(Time))}</td>
<td>{current-grouping-key()[1]}</td>
<td>{current-grouping-key()[3]}</td>
</tr>
</tbody>
</xsl:for-each-group>
</table>
</xsl:template>
<xsl:template match="/">
<html>
<head>
<title>.NET XSLT Fiddle Example</title>
</head>
<body>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/bFWRAp4
Предполагается, что ночная смена всегда прекращается на следующий день, я не уверен, что это реально c, если кто-то выпадет до полуночи из-за болезни.
Я не пытался форматировать даты или время, использую различные format-date
и функции времени, предлагаемые XSLT / XPath.