How to sort the date using XSLT in given format

Viewed 33

I have xml like below

<Root>
  <Element StartDate="2013/12/24"/>
  <Element StartDate="2013/12/20"/>
  <Element StartDate="2013/12/31"/>
  <Element StartDate="2013/12/30"/>
</Root>

How do I get only max date from it using xslt 1.0. Format is YYYY/MM/DD

<Root>
  <Element StartDate="2013/12/31"/>
</Root>
2 Answers

YYYY/MM/DD dates will sort correctly (i.e. in chronological order) when the sort order is alphabetical. To get the latest date, you can do simply:

<xsl:template match="/Root">
    <latest-date>
        <xsl:for-each select="Element">
            <xsl:sort select="@StartDate" data-type="text" order="descending" />
            <xsl:if test="position()=1">
                <xsl:value-of select="@StartDate" />
            </xsl:if>
        </xsl:for-each>
    </latest-date>
</xsl:template>

Note that this is assuming that the format is indeed YYYY/MM/DD - that is with leading zeros for month and day. Your example is ambiguous in this respect.

If it turns out there are day or months numbers without leading zeros (e.g. dates like 2020/8/6 or 2019/5/12), then you can use multiple xsl:sort elements to sort the dates first by year, then by month, and then by day, by extracting the 3 different parts of each date, and by telling xsl:sort to treat the results as numbers (rather than strings) because e.g. 5 comes before 10 numerically, but after it in alphabetical order.

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

<xsl:template match="/Root">
    <latest-date>
        <xsl:for-each select="Element">
            <!-- sort by year... -->
            <xsl:sort select="substring-before(@StartDate, '/')" 
                      data-type="number" order="descending" />
            <!-- ... then by month -->
            <xsl:sort select="substring-before(substring-after(@StartDate, '/'), '/')" 
                      data-type="number" order="descending" />
            <!-- ... then by day -->
            <xsl:sort select="substring-after(substring-after(@StartDate, '/'), '/')" 
                      data-type="number" order="descending" />
            <xsl:if test="position()=1">
                <xsl:value-of select="@StartDate" />
            </xsl:if>
        </xsl:for-each>
    </latest-date>
</xsl:template>

</xsl:stylesheet>
Related