'How to group two siblings with consecutive days in XSLT
I have a requirement to group consecutive days into 1 for the matching ID and am not able to figure out the solution, can someone please guide me on how to approach it.
Here are my input and expected output.
<?xml version='1.0' encoding='UTF-8'?>
<Member>
<Data>
<Id>X0001</Id>
<Date>2022-01-01</Date>
</Data>
<Data>
<Id>X0001</Id>
<Date>2022-01-02</Date>
</Data>
<Data>
<Id>X0001</Id>
<Date>2022-01-03</Date>
</Data>
<Data>
<Id>X0001</Id>
<Date>2022-01-04</Date>
</Data>
<Data>
<Id>X0001</Id>
<Date>2022-01-05</Date>
</Data>
<Data>
<Id>X0001</Id>
<Date>2022-01-08</Date>
</Data>
<Data>
<Id>X0001</Id>
<Date>2022-01-12</Date>
</Data>
<Data>
<Id>X0004</Id>
<Date>2022-01-09</Date>
</Data>
<Data>
<Id>X0005</Id>
<Date>2022-01-10</Date>
</Data>
<Data>
<Id>X0005</Id>
<Date>2022-01-11</Date>
</Data>
</Member>
OUTPUT
----
Out>
<Member>
<Id>X0001</Id
<SDate>2022-01-01</SDate>
<EDate>2022-01-02</EDate
</Member>
<Member>
<Id>X0001</Id
<SDate>2022-01-03</SDate>
<EDate>2022-01-04</EDate
</Member>
<Member>
<Id>X0001</Id
<SDate>2022-01-05</SDate>
<EDate>2022-01-05</EDate
</Member>
<Member>
<Id>X0001</Id
<SDate>2022-01-08</SDate>
<EDate>2022-01-08</EDate
</Member>
<Member>
<Id>X0001</Id
<SDate>2022-01-12</SDate>
<EDate>2022-01-12</EDate
</Member>
<Member>
<Id>X0004</Id
<SDate>2022-01-09</SDate>
<EDate>2022-01-09</EDate
</Member>
<Member>
<Id>X0005</Id
<SDate>2022-01-10</SDate>
<EDate>2022-01-11</EDate
</Member>
</Out>
I need to group if days are consecutive for each ID, if there is no following day then day should be left as is.
Solution 1:[1]
Here is one way you could look at it, I think:
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="xs">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/Member">
<Out>
<!-- group by id -->
<xsl:for-each-group select="Data" group-by="Id">
<!-- group contiguous ranges -->
<xsl:for-each-group select="current-group()" group-starting-with="Data[not(xs:date(Date) = xs:date(preceding-sibling::Data[1]/Date) + xs:dayTimeDuration('P1D'))]">
<!-- divide into pairs -->
<xsl:for-each-group select="current-group()" group-by="(position()-1) idiv 2">
<Member>
<xsl:copy-of select="Id"/>
<SDate>
<xsl:value-of select="Date"/>
</SDate>
<EDate>
<xsl:value-of select="current-group()[last()]/Date"/>
</EDate>
</Member>
</xsl:for-each-group>
</xsl:for-each-group>
</xsl:for-each-group>
</Out>
</xsl:template>
</xsl:stylesheet>
Note that this assumes that within each Id records are already sorted chronologically.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | michael.hor257k |
