XSLT - Getting the first N elements.

I'm new at XSLT and I have a problem:

I'm trying to create a stylesheet with, as input:

<Events>

<Event datetime="2006-10-13T11:20:00">

<Title>blabla</Title>

<Text>blabla</Text>

</Event>

<Event ....

</Events>

as parameters:

$date ; $num

as output: an XHTML showing the first $num elements whose date is > than $date

In my mind the approach will be to order the elements and do a foreach with a if statement to query the elements with a suitable date ... but I need a variable to store the num of elements selected and exit the cycle... It isn't the case, I know.

Can anyone tell me a more clever approach

Thank you.

.utaal



Answer this question

XSLT - Getting the first N elements.

  • windypoint

    Perfect!

    Thank you very much.

    .utaal


  • Thiru_

    Hi there,

    Couple of points, XSLT v1.0 isn't schema aware so you won't be able to treat @datetime as a date value, which means you won't be able to do date > $date. I've had a search through some XSLT reference and there are no date functions so you might be out of luck there. An option might be to write your own XSLT Extension (or see if one already exists) that lets you compare dates. Someone else hear might have a better idea.

    I've done a stylesheet that matches the date values and then returns the top N just to show you how you can go about doing a stylesheet. Hope that is helpful..

    < xml version='1.0' encoding='UTF-8' >
    <xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>

    <xsl:output method="html"/>

    <xsl:variable name="N">2</xsl:variable>
    <xsl:variable name="D">2006-10-13T11:20:00</xsl:variable>

    <xsl:key name="dates" match="/Events/Event" use="@datetime"/>

    <xsl:template match="/">
    <html>
    <body>
    <xsl:for-each select="key('dates', $D)">
    <xsl:if test="position() &lt;= $N">
    <p><xsl:value-of select="."/></p>
    </xsl:if>
    </xsl:for-each>
    </body>
    </html>
    </xsl:template>

    </xsl:stylesheet>



  • Ultimate

    I've noticed that if I put a schema definition reference in the input XML of a XSLT, the parser ignores the templates definition and writes out the XML tag contents (not the tags themselves) as text.

    Why does this happen

    Thanks.

    .utaal


  • General Fault

    Here's a solution which doesn't need any extension function.

    The following transformation:

    <xsl:stylesheet version="1.0"

    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:output omit-xml-declaration="yes" indent="yes"/>

    <xsl:param name="pNDates" select="3"/>

    <xsl:param name="pDate" select="'2006-10-13T00:00:00'"/>

    <xsl:variable name="pnumDate" select=

    "translate($pDate, '-T:','')"/>

    <xsl:template match="/">

    <xsl:for-each select=

    "/*/*[translate(@datetime,'-T:','') > $pnumDate]">

    <xsl:sort select="@datetime"/>

    <xsl:if test="$pNDates >= position()">

    <xsl:copy-of select="."/>

    </xsl:if>

    </xsl:for-each>

    </xsl:template>

    </xsl:stylesheet>

    When applied against this xml document:

    <Events>

    <Event datetime="2006-10-15T00:00:00"/>

    <Event datetime="2006-10-11T00:00:00"/>

    <Event datetime="2006-10-14T00:00:00"/>

    <Event datetime="2006-10-13T00:00:00"/>

    <Event datetime="2006-10-16T00:00:00"/>

    <Event datetime="2006-10-12T00:00:00"/>

    </Events>

    produces the desired result:

    <Event datetime="2006-10-14T00:00:00" />

    <Event datetime="2006-10-15T00:00:00" />

    <Event datetime="2006-10-16T00:00:00" />

    Hope this helped.

    Dimitre Novatchev.


  • Dave Waterworth

    Probably you redefined the default namespace using xmlns="...". If it's still an issue, please open a separate thread.

    Thanks,
    Anton

  • lcj

    MSXML 4.0 and XslCompiledTransform support the ms:string-compare function, which can be used for comparing dates. Suppose you want to extract the first 3 events happened on or after 2006-10-12T00:00:00. You may use the following stylesheet:

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"

          xmlns:ms="urn:schemas-microsoft-com:xslt"

          exclude-result-prefixes="ms"

     

    <xsl:param name="Num" select="3"/>

    <xsl:param name="Date" select="'2006-10-12T00:00:00'"/>

     

    <xsl:template match="Events">

          <xsl:for-each select="Event[ms:string-compare(@datetime, $Date, 'en') >= 0]">

                <xsl:sort select="@datetime" order="ascending"/>

                <xsl:if test="position() &lt;= $Num">

                      <xsl:copy-of select="."/>

                </xsl:if>

          </xsl:for-each>

    </xsl:template>

     

    </xsl:stylesheet>

    Applied to this input file:

    <Events>

    <Event datetime="2006-10-15T00:00:00"/>

    <Event datetime="2006-10-11T00:00:00"/>

    <Event datetime="2006-10-14T00:00:00"/>

    <Event datetime="2006-10-13T00:00:00"/>

    <Event datetime="2006-10-16T00:00:00"/>

    <Event datetime="2006-10-12T00:00:00"/>

    </Events> 

    it returns these three events:

    <Event datetime="2006-10-12T00:00:00" />

    <Event datetime="2006-10-13T00:00:00" />

    <Event datetime="2006-10-14T00:00:00" />

    Thanks,
    Anton


  • XSLT - Getting the first N elements.