Reputation: 47
I would like to seek your expert knowledge on xslt. I have date range coming in XML for e.g.
<data>
<ID>ABC1</ID>
<Start_Date>2018-05-01</Start_Date>
<End_Date>2018-05-10</End_Date>
<data>
<ID>ABC2</ID>
<Start_Date>2018-05-10</Start_Date>
<End_Date>2018-05-12</End_Date>
<data>
<root>
Now I need to send 1 row per date e.g. for ABC1 id I need to send 10 records with startdate enddate as increment.
after transformation the data should look like below
<data>
<ID>ABC1</ID>
<Start_Date>2018-05-01</Start_Date>
<End_Date>2018-05-01</End_Date>
<data>
<data>
<ID>ABC1</ID>
<Start_Date>2018-05-02</Start_Date>
<End_Date>2018-05-02</End_Date>
<data>
<data>
<ID>ABC1</ID>
<Start_Date>2018-05-10</Start_Date>
<End_Date>2018-05-10</End_Date>
<data><root>
till so on so total for ABC1 we need to have 10 data section and for ABC2 2 data section.
Please guide how can I implement the logic in XSLT.
Upvotes: 0
Views: 800
Reputation: 167706
As you say you can use at least XSLT 2 you can exploit the xs:date
data type and the arithmetic operations like substraction XSLT/XPath 2 and later support to compute the difference in days and then process each item that many times with the right date:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="3.0">
<xsl:mode on-no-match="shallow-copy"/>
<xsl:mode name="increment" on-no-match="shallow-copy"/>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="data">
<xsl:variable name="data" select="."/>
<xsl:for-each select="0 to days-from-duration(xs:date(End_Date) - xs:date(Start_Date))">
<xsl:apply-templates select="$data" mode="increment">
<xsl:with-param name="date" tunnel="yes" select="xs:date($data/Start_Date) + xs:dayTimeDuration('P1D') * ."/>
</xsl:apply-templates>
</xsl:for-each>
</xsl:template>
<xsl:template match="data/Start_Date | data/End_Date" mode="increment">
<xsl:param name="date" tunnel="yes"/>
<xsl:copy>
<xsl:value-of select="$date"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
That is XSLT 3, but only for the xsl:mode
stuff you could replace for XSLT 2 with
<xsl:template match="@* | node()" mode="#default increment">
<xsl:copy>
<xsl:apply-templates select="@* | node()" mode="#current"/>
</xsl:copy>
</xsl:template>
XSLT 3 online sample at https://xsltfiddle.liberty-development.net/gWmuiJ6.
Upvotes: 1