I have the following xml:
<?xml version="1.0" encoding="UTF-8"?>
<divisions>
<userProvidedEffDate>12/31/2002</userProvidedEffDate>
<division>
<GroupNumber>001</GroupNumber>
<GroupEffDt>01/01/2000</GroupEffDt>
<GroupExpDt>12/31/9999</GroupExpDt>
</division>
<division>
<GroupNumber>002</GroupNumber>
<GroupEffDt>01/01/2000</GroupEffDt>
<GroupExpDt>12/31/2001</GroupExpDt>
</division>
</divisions>
Now I want to tranasform the above xml using XSLT 1.0 based on the value of <userProvidedEffDate>
. If the <userProvidedEffDate>
is in between the date range of the <division>'s
<GroupEffDt>
and <GroupExpDt>
(inclusive), then we display that division. For example the above input xml should be transformed as below based on the <userProvidedEffDate>
value 12/31/2002.
<?xml version="1.0" encoding="UTF-8"?>
<divisions>
<userProvidedEffDate>12/31/2002</userProvidedEffDate>
<division>
<GroupNumber>001</GroupNumber>
<GroupEffDt>01/01/2000</GroupEffDt>
<GroupExpDt>12/31/9999</GroupExpDt>
</division>
</divisions>
Any help is appreciated.
As an example of why you switch to Saxon 9, if you had to do this in XSLT 1.0 (without any extension functions) you would have to convert the dates into a number of the form YYYYMMDD.
For example
<xsl:variable name="userProvidedEffDate" select="number(concat(substring(userProvidedEffDate, 7, 4), substring(userProvidedEffDate, 1, 2), substring(userProvidedEffDate, 4, 2)))" />
Try this XSLT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="divisions">
<xsl:variable name="userProvidedEffDate" select="number(concat(substring(userProvidedEffDate, 7, 4), substring(userProvidedEffDate, 1, 2), substring(userProvidedEffDate, 4, 2)))" />
<xsl:copy>
<xsl:apply-templates select="@*|userProvidedEffDate" />
<xsl:apply-templates select="division
[number(concat(substring(GroupEffDt, 7, 4), substring(GroupEffDt, 1, 2), substring(GroupEffDt, 4, 2))) <= $userProvidedEffDate
and number(concat(substring(GroupExpDt, 7, 4), substring(GroupExpDt, 1, 2), substring(GroupExpDt, 4, 2))) >= $userProvidedEffDate]" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Of course, if you had control over the XML, an easy solution would be to have the dates in YYYYMMDD format in the XML in the first place
This is tedious, but not too difficult:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/divisions">
<xsl:variable name="userDate">
<xsl:value-of select="substring(userProvidedEffDate, 7, 4)"/>
<xsl:value-of select="substring(userProvidedEffDate, 1, 2)"/>
<xsl:value-of select="substring(userProvidedEffDate, 4, 2)"/>
</xsl:variable>
<xsl:copy>
<xsl:for-each select="division">
<xsl:variable name="effDate">
<xsl:value-of select="substring(GroupEffDt, 7, 4)"/>
<xsl:value-of select="substring(GroupEffDt, 1, 2)"/>
<xsl:value-of select="substring(GroupEffDt, 4, 2)"/>
</xsl:variable>
<xsl:variable name="expDate">
<xsl:value-of select="substring(GroupExpDt, 7, 4)"/>
<xsl:value-of select="substring(GroupExpDt, 1, 2)"/>
<xsl:value-of select="substring(GroupExpDt, 4, 2)"/>
</xsl:variable>
<xsl:if test="$effDate <= $userDate and $userDate <= $expDate">
<xsl:copy-of select="."/>
</xsl:if>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>