DannyBoy
DannyBoy

Reputation: 107

xsl template with match that compares dates

I have the following XML

<LIST>
  <FIELD name="D22" value="2005-05-03Z" />
  <ELEMENT name="QX55">
    <ELEMENT name="QX553" value="2004-01-01Z" />
  </ELEMENT>
  <ELEMENT name="QX55">
    <ELEMENT name="QX553" value="2005-04-26Z" />
  </ELEMENT>
  <ELEMENT name="QX55">
    <ELEMENT name="QX553" value="2005-05-01Z" />
  </ELEMENT>
  <ELEMENT name="QX55">
    <ELEMENT name="QX553" value="2006-01-01Z" />
  </ELEMENT>
  <ELEMENT name="QX55">
    <ELEMENT name="QX553" value="2005-05-03Z" />
  </ELEMENT>
</LIST>

I am trying to create a xslt mapping that would remove all QX25 elements with @value date before the date in @value field D22

I am applying the filter by using the element:

<xsl:template match="">

I know that xslt cannot compare dates so I suspect this would have to be done by substring but I don't know how to apply substring in the match attribute. Also I cannot use any extensions to xslt

This is what I tried so far: I only tried to get it working for comparing years so far but it's giving me a parse exception

<xsl:variable name="d22date">
        <xsl:value-of select="/LIST/FIELD[@name='D22']/@value" />
</xsl:variable>

<xsl:template match="//ELEMENT[@name='QX55'][ELEMENT[@name='QX553' and substring(@value,0,5)<substring($d22date,0,5)]]"/>

Can anyone help me with this match attribute?

I am using xslt 2.0

Upvotes: 1

Views: 753

Answers (1)

Tim C
Tim C

Reputation: 70638

You are not far off, but there are a few things wrong with your current attempt:

  • < needs to be escaped as &lt; in the expression
  • Indexing of characters in substring starts at 1, not 0.
  • The length of the date string you want is 10, not 5

This means your template should really look like this:

<xsl:template match="ELEMENT
                     [@name='QX55']
                     [ELEMENT[@name='QX553' and substring(@value, 1, 10) &lt; substring($d22date, 1, 10)]]"/>

Note that it is not true to say that XSLT can't compare dates. XSLT 2.0 does have many date/time functions. For example, you could write your XSLT like this

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xsl:output method="xml" indent="yes" />

    <xsl:variable name="d22date" select="/LIST/FIELD[@name='D22']/@value" as="xs:date" />

    <xsl:template match="ELEMENT[@name='QX55'][ELEMENT[@name='QX553' and xs:date(@value) &lt; $d22date]]"/>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

Upvotes: 1

Related Questions