Reputation: 29
I am working with the following XML structure.
<File>
<Record>
<ID>01234</ID>
<Description>Sample description</Description>
<StartDate>2021-01-29</StartDate>
<EndDate>2021-02-02</EndDate>
</Record>
<Record>
<ID>56789</ID>
<Description>Sample description</Description>
<StartDate>2021-02-03</StartDate>
<EndDate>2021-02-06</EndDate>
</Record>
I need to create a Record element for each date in between, and including, the given StartDate and EndDate. My resulting XML needs to look like the following.
<File>
<Record>
<ID>01234</ID>
<Description>Sample description</Description>
<EventDate>2021-01-29</EventDate>
</Record>
<Record>
<ID>01234</ID>
<Description>Sample description</Description>
<EventDate>2021-01-30</EventDate>
</Record>
<Record>
<ID>01234</ID>
<Description>Sample description</Description>
<EventDate>2021-01-31</EventDate>
</Record>
<Record>
<ID>01234</ID>
<Description>Sample description</Description>
<EventDate>2021-02-01</EventDate>
</Record>
<Record>
<ID>01234</ID>
<Description>Sample description</Description>
<EventDate>2021-02-02</EventDate>
</Record>
<Record>
<ID>56789</ID>
<Description>Sample description</Description>
<EventDate>2021-02-03</EventDate>
</Record>
<Record>
<ID>56789</ID>
<Description>Sample description</Description>
<EventDate>2021-02-04</EventDate>
</Record>
<Record>
<ID>56789</ID>
<Description>Sample description</Description>
<EventDate>2021-02-05</EventDate>
</Record>
<Record>
<ID>56789</ID>
<Description>Sample description</Description>
<EventDate>2021-02-06</EventDate>
</Record>
Research I've done thus far hasn't given me much and, given my XSLT knowledge is severely lacking, I'd greatly appreciate any assistance. My preference would be not to use a recursive function (possibly XSLT 3.0??) but at this point I'll go with anything.
Thank you.
Upvotes: 1
Views: 528
Reputation: 2714
Here's a way this could be done:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
version="3.0">
<xsl:mode on-no-match="shallow-copy"/>
<xsl:output method="xml"/>
<xsl:template match="Record">
<xsl:variable name="currentRec" select="."/>
<xsl:variable name="numberDays" select="xs:integer((xs:date(EndDate) - xs:date(StartDate)) div xs:dayTimeDuration('P1D'))"/>
<xsl:for-each select="0 to $numberDays">
<Record>
<xsl:copy-of select="$currentRec/ID"/>
<xsl:copy-of select="$currentRec/Description"/>
<EventDate><xsl:value-of select="xs:date($currentRec/StartDate) + (xs:dayTimeDuration('P1D')*(position()-1))"/></EventDate>
</Record>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
See it working here : https://xsltfiddle.liberty-development.net/ei5R4uW/1
Upvotes: 0
Reputation: 167706
You could use
<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 indent="yes"/>
<xsl:template match="Record">
<xsl:apply-templates select="(0 to days-from-duration(xs:date(EndDate) - xs:date(StartDate))) ! current()" mode="split"/>
</xsl:template>
<xsl:template match="Record" mode="split">
<xsl:copy>
<xsl:apply-templates select="* except (StartDate, EndDate)"/>
<EventDate>{xs:date(StartDate) + xs:dayTimeDuration('P1D') * (position() - 1)}</EventDate>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Upvotes: 1