3

Does anyone know of a way to do this kind of sorting in XSL?

Here's what I have so far but it only sorts by day and ignores the rest of the date.

      <xsl:apply-templates select="item">
          <xsl:sort select="pubDate" data-type="text" order="descending"/>
      </xsl:apply-templates>
AdamRox
  • 85
  • 9
  • 2
    The date is just the date or date-time? Are you using XSLT 1.0 or XSLT 2.0? Also you could you edit your answer posting your XML? – Pablo Pozo Feb 21 '13 at 22:08
  • 1
    It's certainly possible but not trivial. You have to write a parser in XSLT that converts RFC-822 dates to something sortable. I'd go with EXSLT functions and the XPath string functions. – nwellnhof Feb 21 '13 at 23:33
  • 1
    this can be helpful http://www.codeproject.com/Articles/4261/Sorting-dates-in-XSL – Vinit Feb 22 '13 at 02:04

1 Answers1

2

Thanks for the quick responses guys. Got me going in the right direction. Managed to solve it! Found a useful link http://blog.mastykarz.nl/how-to-do-it-rss-aggregation-merging-multiple-xml-files-using-xslt/

I was using XSLT Version 2.0. Just a case using a variable to substitute in the MMM months and sub-stringing the date down.

SOLUTION

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:variable name="Months" select="'Jan;Feb;Mar;Apr;May;Jun;Jul;Aug;Sep;Oct;Nov;Dec'"/>

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

<xsl:template match="channel">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()[not(preceding-sibling::item) and not(self::item)]"/>
        <xsl:apply-templates select="item">
            <!-- year -->
        <xsl:sort select="substring(pubDate, 13, 4)" order="descending" data-type="number"/>
        <!-- month -->
        <xsl:sort select="string-length(substring-before($Months, substring(pubDate, 9, 3)))" order="descending" data-type="number"/>
        <!-- day -->
        <xsl:sort select="substring(pubDate, 6, 2)" order="descending" data-type="number"/>
        <!-- hour -->
        <xsl:sort select="substring(pubDate, 18, 2)" order="descending" data-type="number"/>

        </xsl:apply-templates>
        <xsl:apply-templates select="@*|node()[not(following-sibling::item) and not(self::item)]"/>
</xsl:copy>
</xsl:template>

AdamRox
  • 85
  • 9
  • 1
    This solution seems very brittle as it assumes that the date-time elements are always at the same position in the string. This is not necessarily true. For example, the day of the week at the beginning of date-time is optional. Also, day of month might be specified using one or two digits. – nwellnhof Feb 23 '13 at 11:23
  • 1
    @nwellnhof That shouldn't be true if they are using RFC-822 dates. I'm assuming that the OP is using an RSS feed and in order for it to validate, pubDate has very strict requirements. Now, it's true that pubDate doesn't have to be in the format, but it does to validate. – doubleJ Nov 07 '13 at 19:58