web-dev-qa-db-fra.com

Formater une date en XML via XSLT

Lorsque j'utilise le sérialiseur XML pour sérialiser un DateTime, il est écrit au format suivant:

<Date>2007-11-14T12:01:00</Date>

Lorsque je passe ceci dans une feuille de style XSLT pour sortir du HTML, comment puis-je formater cela? Dans la plupart des cas, j'ai juste besoin de la date, et quand j'ai besoin de temps, je ne veux bien sûr pas le "T drôle" là-dedans.

36
peterchen

Voici quelques modèles 1.0 que vous pouvez utiliser: -

<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>

Appelez-les avec: -

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

et

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

où xpath est le chemin d'accès à un élément ou un attribut qui a le format d'heure de date standard.

65
AnthonyWJones

Le formatage de la date n'est pas facile dans XSLT 1.0. La façon la plus élégante est probablement d'écrire une fonction d'extension XSLT courte en C # pour le formatage de la date. Voici un exemple:

<?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>

Avec ce document d'entrée

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

tu auras

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

La fonction formatant la date prend une valeur de date sous forme de chaîne et un format tel que décrit dans Méthode DateTime.ToString . L'utilisation de la structure DateTime de .NET vous permet d'analyser gratuitement les valeurs de date/heure XSD arbitraires (y compris les spécificateurs de fuseau horaire), le calcul du fuseau horaire et la sortie localisée.

Cependant, sachez qu'il y en a un mise en garde (http://support.Microsoft.com/kb/316775) avec des extensions de script msxml: chaque fois que vous chargez le XSLT, un assembly contenant le code de script est généré dynamiquement et chargé en mémoire. En raison de la conception du runtime .NET, cet assembly ne peut pas être déchargé. C'est pourquoi vous devez vous assurer que votre XSLT n'est chargé qu'une seule fois (puis mis en cache pour une réutilisation ultérieure). Ceci est particulièrement important lors de l'exécution dans IIS.

25
Dirk Vollmar

John Workman discute longuement de cette question et donne plusieurs solutions dans ce discussion[1] sur son blog. Fondamentalement, analysez les composants de date individuels et recombinez dans l'ordre que vous souhaitez. Pour votre cas, une version XSLT 1.0+ pure serait:

<?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>

Un autre format (REMPLACE la section FORMAT EUROPÉEN):

<!-- 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 -->

Vous pouvez recombiner les éléments comme vous le souhaitez.

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

9
rivy

Toutes mes excuses pour avoir commenté ce vieux fil, mais pour d'autres le trouvant comme moi, vous pouvez également utiliser javascript si vous utilisez un transformateur MS:

Déclarez l'espace de noms "msxsl":

xmlns:msxsl="urn:schemas-Microsoft-com:xslt" 

Déclarez un espace de noms pour votre script:

xmlns:js="urn:custom-javascript" 

(Facultatif) Omettez les préfixes de la sortie:

exclude-result-prefixes="msxsl js" 

Vous vous retrouvez donc avec une déclaration xsl comme celle-ci:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
  xmlns:msxsl="urn:schemas-Microsoft-com:xslt"
  xmlns:js="urn:custom-javascript"
  exclude-result-prefixes="msxsl js">

Écrivez le JavaScript dans l'élément de script msxsl::

<msxsl:script language="JavaScript" implements-prefix="js"> 
<![CDATA[ 
function javascriptFunction(dateValue){
  var date = new Date(dateValue);
  if(!isNaN(date)) return date.toLocaleString();
  return dateValue;
}
]]>
</msxsl:script>

Appelez votre fonction JavaScript (en utilisant la syntaxe XPath '.' Désignant 'ce nœud'):

<xsl:value-of select="js:javascriptFunction(string(.))"/>

NB: Au moment de l'écriture, il ne semble pas y avoir de moyen (xsl) pour inclure des fichiers js externes (par exemple la bibliothèque jquery). Cela pourrait être fait en analysant le côté serveur de fichiers xsl avant la transformation et en ajoutant le contenu du fichier js sous forme de chaîne dans une section CDATA. J'ai commencé à suivre cette voie moi-même, mais j'ai conclu que si vous avez besoin de ce niveau de fonctionnalité, il pourrait être mieux placé dans une autre partie du pipeline.

source: http://dev.ektron.com/kb_article.aspx?id=482
ref: http://www.ibm.com/developerworks/xml/library/x-tipxsltjs/index.html

5
Phileas Fogg

Merci, ce message a beaucoup aidé.

Je transformais un flux RSS qui utilise le format de date suivant: lun, 04 avr 2011 23:18:00 -07. Voici le modèle nommé que j'ai utilisé pour l'analyser.

<!--Parse date format: Mon, 04 Apr 2011 23:18:00 -0700-->
<xsl:template name="formatDate">

    <xsl:param name="dateIn" />

    <xsl:variable name="day" select="substring($dateIn, 0, 3)" />
    <xsl:variable name="date" select="substring($dateIn, 6, 2)" />
    <xsl:variable name="month" select="substring($dateIn, 9, 3)" />
    <xsl:variable name="year" select="substring($dateIn, 13, 4)" />

    <xsl:variable name="hour" select="substring($dateIn, 18, 2)" />
    <xsl:variable name="min" select="substring($dateIn, 21, 2)" />
    <xsl:variable name="sec" select="substring($dateIn, 24, 2)" />

    <xsl:value-of select="concat($date, ' ', $month, ' ', $year, ' ', $hour, ':', $min, ':', $sec)" />

</xsl:template>
3
Jibran

correction au poste de roy: le jour de la fonction aura toujours la valeur du mois. Utilisez le suivant:

<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)" />

<xsl:value-of select="concat($month,'/',$day,'/',$year,' ',$hh,':',$mm,':',$ss)" />
3
Andy