Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

XSLT1.0/XPath 1.0 Selecting nodes by date range. Is this even possible?

Tags:

xslt

xpath

Lets say I have a list of nodes that contain an attribute datetime, and I want to select only the records that occur after $compare-datetime.

<records>
    <record @datetime="2010-01-04T16:48:15.501-05:00"/>
    <record @datetime="2010-01-03T16:48:15.501-05:00"/>
    ...etc...
</records>

In xquery to select items within a date range I would do

/records/record[xs:dateTime(@datetime) > xs:dateTime($compare-datetime)]

However in XSLT 1.0 I have tried alot of different approaches and alot of searching for answers, without any luck at getting this to work.

I am beginning to think that short of parsing the actual dateTime to an integer value, this is not a simple task in xslt.

I am hoping someone can give me a definite answer on that so I can at least know what I am up against.

Cheers,

Casey

like image 599
Casey Jordan Avatar asked Jan 06 '11 18:01

Casey Jordan


People also ask

What happens if a template XPath does not match anything?

When it matches an XML node, the template is invoked by the processor. <xsl: template match> matches the root node of the source document. If it doesn't find the match nodes, default rules are applied. The match follows an expression of Xpath.

How do I find the difference between two dates in XSLT?

You get current date-time by http://exslt.org/date/functions/date-time/index.html extension function. http://exslt.org/date/functions/difference/index.html extension function calculates the duration you want.

How can I get current date and time in XSLT?

The function current-dateTime() returns the current time including milliseconds, for example: 2008-05-07T18:12:23.593+03:00 where . 593 represents the milliseconds. If you want to extract only a fragment of the returned time you can apply the format-dateTime() function to the result of current-dateTime().

What is node set in XSLT?

A node set is a set of nodes. When you write an XPath expression to return one or more nodes, you call these nodes a node set. For example, if you use the following expression to return a node called title , you will have a set of nodes all called title (assuming there's more than one record). child::title.


3 Answers

If the dates will always be in the same time zone, and have fixed-width fields (constant number of digits in each field), I believe you could take this approach: remove punctuation, leaving the numbers, and compare the numbers.

<xsl:variable name="datetime-punctuation" select="'-.:T'" />
<xsl:variable name="stripped-compare-datetime"
  select="number(translate($compare-datetime, $datetime-punctuation, ''))" />

Then use

/records/record[number(translate(@datetime, $datetime-punctuation, ''))
                 > $stripped-compare-datetime)]
like image 109
LarsH Avatar answered Nov 15 '22 10:11

LarsH


May be it's not the best solution, but I have this:

XML input:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="dates.xsl"?>
<records>
    <record datetime="2010-01-04T16:48:15.501-05:00"/>
    <record datetime="2011-01-04T16:48:15.501-05:00"/>
</records>

XSLT:

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:date="http://exslt.org/dates-and-times"
    extension-element-prefixes="date">
    <xsl:import href="date.difference.template.xsl"/>
    <!-- http://exslt.org/date/functions/difference/date.difference.template.xsl -->
    <xsl:output method="xml" indent="yes"/>        

    <xsl:template match="/*">
        <xsl:copy>
            <result1>
                <xsl:call-template name="date:difference">
                   <xsl:with-param name="start" select="record[1]/@datetime"/>
                   <xsl:with-param name="end" select="'2010-04-04T16:48:15.501-05:00'"/>
                </xsl:call-template>
            </result1>
            <result2>
                <xsl:call-template name="date:difference">
                   <xsl:with-param name="start" select="record[2]/@datetime"/>
                   <xsl:with-param name="end" select="'2010-04-04T16:48:15.501-05:00'"/>
                </xsl:call-template>
            </result2>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

Result:

<records>
    <result1>P90D</result1>
    <result2>-P275D</result2>
</records>

Negative difference would mean that first date occurs after the second date.

like image 22
Flack Avatar answered Nov 15 '22 10:11

Flack


I am afraid that XSLT 1.0 has no built-in support for dateTimes. It's possible that you may find that someone has written a library - have a look on the XSLT FAQ

See http://www.dpawson.co.uk/xsl/rev2/dates.html#d14938e16 for what XSLT 2.0 can offer.

like image 35
peter.murray.rust Avatar answered Nov 15 '22 11:11

peter.murray.rust