Finding whether a date falls within the date range

2019-08-29 03:12发布

问题:

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.

回答1:

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))) &lt;= $userProvidedEffDate
                                      and number(concat(substring(GroupExpDt, 7, 4), substring(GroupExpDt, 1, 2), substring(GroupExpDt, 4, 2))) &gt;= $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



回答2:

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 &lt;= $userDate and $userDate &lt;= $expDate">
                <xsl:copy-of select="."/>
            </xsl:if>
        </xsl:for-each>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>


标签: xslt