Search code examples
xpathxslt-2.0

Check difference between two dates using XSLT


1]I have below input xml1:

<TimeLimit Start="2022-02-24" End="2022-03-04"/>
<Tasks>
  <TaskRate RateCode="Test">
    <Rates>
       <Rate BeginDate="2022-02-24" EndDate="2022-02-25" >
        <Base Amount="100.00" CurrencyCode="EUR"/>
       </Rate>
      <Rate BeginDate="2022-02-26" EndDate="2022-03-01" >
       <Base Amount="200.00" CurrencyCode="EUR"/>
      </Rate>
      <Rate BeginDate="2022-03-02" EndDate="2022-03-03" >
       <Base Amount="200.00" CurrencyCode="EUR"/>
      </Rate>
   </Rates>
  </TaskRate>
</Tasks>

I want output as below:

<TimeLimit Start="2022-02-24" End="2022-03-04"/>
<Tasks>
  <TaskRate RateCode="Test">
    <Rates>
       <Rate BeginDate="2022-02-24" EndDate="2022-02-25" >
        <Base Amount="100.00" CurrencyCode="EUR"/>
       </Rate>
      <Rate BeginDate="2022-02-25" EndDate="2022-03-02" >
       <Base Amount="200.00" CurrencyCode="EUR"/>
      </Rate>
      <Rate BeginDate="2022-03-02" EndDate="2022-03-04" >
       <Base Amount="200.00" CurrencyCode="EUR"/>
      </Rate>
   </Rates>
  </TaskRate>
</Tasks>

2]And when i have below input xml2:

<TimeLimit Start="2022-02-24" End="2022-03-04"/>
<Tasks>
  <TaskRate RateCode="Test">
    <Rates>
       <Rate BeginDate="2022-02-24" EndDate="2022-02-26" >
        <Base Amount="100.00" CurrencyCode="EUR"/>
       </Rate>
      <Rate BeginDate="2022-02-26" EndDate="2022-03-02" >
       <Base Amount="200.00" CurrencyCode="EUR"/>
      </Rate>
      <Rate BeginDate="2022-03-02" EndDate="2022-03-04" >
       <Base Amount="200.00" CurrencyCode="EUR"/>
      </Rate>
   </Rates>
  </TaskRate>
</Tasks>

Then i want output as below:

<TimeLimit Start="2022-02-24" End="2022-03-04"/>
<Tasks>
  <TaskRate RateCode="Test">
    <Rates>
       <Rate BeginDate="2022-02-24" EndDate="2022-02-26" >
        <Base Amount="100.00" CurrencyCode="EUR"/>
       </Rate>
      <Rate BeginDate="2022-02-26" EndDate="2022-03-02" >
       <Base Amount="200.00" CurrencyCode="EUR"/>
      </Rate>
      <Rate BeginDate="2022-03-02" EndDate="2022-03-04" >
       <Base Amount="200.00" CurrencyCode="EUR"/>
      </Rate>
   </Rates>
  </TaskRate>
</Tasks>

That means for continuous or non continuous date range as input i always want a output xml with continuous date range. I am using below XSLT code, but its not working:

<Rates>
<xsl:for-each select="Rates/Rate">
<Rate>
<xsl:if test="@BeginDate and not(@BeginDate='')">
<xsl:attribute name="BeginDate">
<xsl:value-of select="@BeginDate" />
</xsl:attribute>
</xsl:if>
<xsl:choose>
<xsl:when test="(xs:date(following-sibling::Rate[1]/@BeginDate) - xs:date(@EndDate)) = 1">
<xsl:attribute name="EndDate">
<xsl:value-of select="xs:date(@EndDate)+xs:dayTimeDuration('P1D')" />
</xsl:attribute>
</xsl:when>
<xsl:otherwise>
<xsl:if test="@EndDate and not(@EndDate='')">
<xsl:attribute name="EndDate">
<xsl:value-of select="@EndDate" />
</xsl:attribute>
</xsl:if>
</xsl:otherwise>
</xsl:choose>
<xsl:choose>
<xsl:when test="xs:date(/TimeLimit/@End) - @EndDate = 1">
<xsl:attribute name="EndDate">
<xsl:value-of select="xs:date(@EndDate)+xs:dayTimeDuration('P1D')" />
</xsl:attribute>
</xsl:when>
<xsl:otherwise>
<xsl:if test="@EndDate and not(@EndDate='')">
<xsl:attribute name="EndDate">
<xsl:value-of select="@EndDate" />
</xsl:attribute>
</xsl:if>
</xsl:otherwise>
</xsl:choose>

</Rate>
</xsl:for-each>
</Rates>

Can someone please help?


Solution

  • In the following xslt I made 2 assumptions:

    Dates can differ more than just one day and TimeLimit/@start should also be respected. Then no date-calculation is needed. Please let me know if that is correct?

    Since your xml did not had a root-element, this is xml I used:

    <TasksGroup>
      <TimeLimit Start="2022-02-24" End="2022-03-04"/>
      <Tasks>
        <TaskRate RateCode="Test">
          <Rates>
            <Rate BeginDate="2022-02-24" EndDate="2022-02-25" >
              <Base Amount="100.00" CurrencyCode="EUR"/>
            </Rate>
            <Rate BeginDate="2022-02-26" EndDate="2022-03-01" >
              <Base Amount="200.00" CurrencyCode="EUR"/>
            </Rate>
            <Rate BeginDate="2022-03-02" EndDate="2022-03-03" >
              <Base Amount="200.00" CurrencyCode="EUR"/>
            </Rate>
          </Rates>
        </TaskRate>
      </Tasks>  
    </TasksGroup>
    

    And this the xslt

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="2.0" 
      xmlns:xs="http://www.w3.org/2001/XMLSchema"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      exclude-result-prefixes="#all">
      
      <xsl:output method="xml"  encoding="UTF-8" indent="yes"/>
      
      <xsl:strip-space elements="*"/>
      
      <xsl:template match="@*|node()">
        <xsl:copy>
          <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
      </xsl:template>
      
      <xsl:variable name="timeLimt" as="element()" select="/*/TimeLimit[1]"/>
    
      <xsl:template match="Rate">
        <xsl:copy>
          <xsl:choose>
            <xsl:when test="position()=1">
              <xsl:attribute name="BeginDate">
                <xsl:value-of select="$timeLimt/@Start" />
              </xsl:attribute>
            </xsl:when>
            <xsl:when test="@BeginDate[not(.='')]">
              <xsl:copy-of select="@BeginDate"/>
            </xsl:when>
          </xsl:choose>
          <xsl:choose>
            <xsl:when test="position()=last()">
              <xsl:attribute name="EndDate">
                <xsl:value-of select="$timeLimt/@End" />
              </xsl:attribute>
            </xsl:when>
            <xsl:when test="following-sibling::*[1][@BeginDate[not(.='')]]">
              <xsl:attribute name="EndDate">
                <xsl:value-of select="following-sibling::*[1]/@BeginDate" />
              </xsl:attribute>
            </xsl:when>
            <xsl:when test="@EndDate[not(.='')]">
              <xsl:copy-of select="@EndDate"/>
            </xsl:when>
          </xsl:choose>
          <xsl:apply-templates/>
        </xsl:copy>
      </xsl:template>
      
    </xsl:stylesheet>
    

    results in this:

    <TasksGroup>
       <TimeLimit Start="2022-02-24" End="2022-03-04"/>
       <Tasks>
          <TaskRate RateCode="Test">
             <Rates>
                <Rate BeginDate="2022-02-24" EndDate="2022-02-26">
                   <Base Amount="100.00" CurrencyCode="EUR"/>
                </Rate>
                <Rate BeginDate="2022-02-26" EndDate="2022-03-02">
                   <Base Amount="200.00" CurrencyCode="EUR"/>
                </Rate>
                <Rate BeginDate="2022-03-02" EndDate="2022-03-04">
                   <Base Amount="200.00" CurrencyCode="EUR"/>
                </Rate>
             </Rates>
          </TaskRate>
       </Tasks>
    </TasksGroup>