Format a date in XML via XSLT Format a date in XML via XSLT xml xml

Format a date in XML via XSLT


Here are a couple of 1.0 templates that you can use:-

<xsl:template name="formatDate">    <xsl:param name="dateTime" />    <xsl:variable name="date" select="substring-before($dateTime, 'T')" />    <xsl:variable name="year" select="substring-before($date, '-')" />    <xsl:variable name="month" select="substring-before(substring-after($date, '-'), '-')" />    <xsl:variable name="day" select="substring-after(substring-after($date, '-'), '-')" />    <xsl:value-of select="concat($day, ' ', $month, ' ', $year)" /></xsl:template><xsl:template name="formatTime">    <xsl:param name="dateTime" />    <xsl:value-of select="substring-after($dateTime, 'T')" /></xsl:template>

Call them with:-

    <xsl:call-template name="formatDate">        <xsl:with-param name="dateTime" select="xpath" />    </xsl:call-template>

and

    <xsl:call-template name="formatTime">        <xsl:with-param name="dateTime" select="xpath" />    </xsl:call-template>

where xpath is the path to an element or attribute that has the standard date time format.


Date formatting is not easy in XSLT 1.0. Probably the most elegant way is to write a short XSLT extension function in C# for date formatting. Here's an example:

<?xml version="1.0" encoding="utf-8"?><xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"                xmlns:msxsl="urn:schemas-microsoft-com:xslt"                xmlns:myExtension="urn:myExtension"                exclude-result-prefixes="msxsl myExtension">  <xsl:output method="xml" indent="yes"/>  <msxsl:script implements-prefix="myExtension" language="C#">    <![CDATA[      public string FormatDateTime(string xsdDateTime, string format)      {          DateTime date = DateTime.Parse(xsdDateTime);          return date.ToString(format);       }    ]]>  </msxsl:script>  <xsl:template match="date">    <formattedDate>      <xsl:value-of select="myExtension:FormatDateTime(self::node(), 'd')"/>    </formattedDate>  </xsl:template></xsl:stylesheet>

With this input document

<?xml version="1.0" encoding="utf-8"?><date>2007-11-14T12:01:00</date>

you will get

<?xml version="1.0" encoding="utf-8"?><formattedDate>14.11.2007</formattedDate> 

The function formatting the date takes a date value as string and a format as described in DateTime.ToString Method. Using .NET's DateTime struct gives you parsing arbitrary XSD datetime values (including time zone specifiers), timezone calculation and localized output for free.

However, be aware that there is one caveat (http://support.microsoft.com/kb/316775) with msxml script extensions: Each time you load the XSLT an assembly containing the script code is generated dynamically and loaded into memory. Due to the design of the .NET runtime, this assembly cannot be unloaded. That's why you have to make sure that your XSLT is only loaded once (and then cached for further re-use). This is especially important when running inside IIS.


John Workman discusses this issue at length and gives several solutions in this discussion[1] on his blog. Basically, parse the individual date components and recombine in whatever order you wish. For your case, a pure XSLT 1.0+ version would be:

<?xml version="1.0" encoding="utf-8"?><xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"><xsl:template match="date"><!-- converts FROM <date>2001-12-31T12:00:00</date> TO some new format (DEFINED below) --><xsl:template name="FormatDate"><xsl:param name="DateTime" /><xsl:variable name="year" select="substring($DateTime,1,4)" /><xsl:variable name="month-temp" select="substring-after($DateTime,'-')" /><xsl:variable name="month" select="substring-before($month-temp,'-')" /><xsl:variable name="day-temp" select="substring-after($month-temp,'-')" /><xsl:variable name="day" select="substring($day-temp,1,2)" /><xsl:variable name="time" select="substring-after($DateTime,'T')" /><xsl:variable name="hh" select="substring($time,1,2)" /><xsl:variable name="mm" select="substring($time,4,2)" /><xsl:variable name="ss" select="substring($time,7,2)" /><!-- EUROPEAN FORMAT --><xsl:value-of select="$day"/><xsl:value-of select="'.'"/> <!--18.--><xsl:value-of select="$month"/><xsl:value-of select="'.'"/> <!--18.03.--><xsl:value-of select="$year"/><xsl:value-of select="' '"/> <!--18.03.1976 --><xsl:value-of select="$hh"/><xsl:value-of select="':'"/> <!--18.03.1976 13: --><xsl:value-of select="$mm"/><xsl:value-of select="':'"/> <!--18.03.1976 13:24 --><xsl:value-of select="$ss"/> <!--18.03.1976 13:24:55 --><!-- END: EUROPEAN FORMAT --></xsl:template>

Another format (REPLACEs the EUROPEAN FORMAT section):

<!-- Long DATE FORMAT --><xsl:choose><xsl:when test="$month = '1' or $month= '01'">January</xsl:when><xsl:when test="$month = '2' or $month= '02'">February</xsl:when><xsl:when test="$month= '3' or $month= '03'">March</xsl:when><xsl:when test="$month= '4' or $month= '04'">April</xsl:when><xsl:when test="$month= '5' or $month= '05'">May</xsl:when><xsl:when test="$month= '6' or $month= '06'">June</xsl:when><xsl:when test="$month= '7' or $month= '07'">July</xsl:when><xsl:when test="$month= '8' or $month= '08'">August</xsl:when><xsl:when test="$month= '9' or $month= '09'">September</xsl:when><xsl:when test="$month= '10'">October</xsl:when><xsl:when test="$month= '11'">November</xsl:when><xsl:when test="$month= '12'">December</xsl:when></xsl:choose> <xsl:value-of select="' '"/> <!--January --><xsl:value-of select="$day"/> <!--January 12 --><xsl:value-of select="','"/> <!--January 12,--><xsl:value-of select="' '"/> <!--January 12, --><xsl:value-of select="$year"/> <!--January 12, 2001--><!-- END: Long DATE FORMAT -->

You can recombine the elements in any way you choose.

[1] http://geekswithblogs.net/workdog/archive/2007/02/08/105858.aspx @@ http://archive.is/4Hjep