2009-02-01 17 views
35

Cuando utilizo el serializador XML para serializar un DateTime, está escrito en el siguiente formato:Formato una fecha en XML a través de XSLT

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

Al pasar esto a través de una hoja de estilo XSLT para la salida HTML, ¿cómo puedo formatear esto? En la mayoría de los casos solo necesito la fecha, y cuando necesito el tiempo, por supuesto, no quiero la "T divertida" allí.

+2

Es muy importante indicar la versión y XSLT plataforma – AnthonyWJones

+3

Es más probable XSLT 1.0 y .NET porque la pregunta está etiquetada con C# –

+0

@divo: bien visto – AnthonyWJones

Respuesta

65

Aquí hay un par de 1.0 plantillas que se pueden utilizar: -

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

Llámenlos con: -

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

y

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

donde XPath es el camino hacia un elemento o atributo que tiene el formato de fecha y hora estándar.

+13

XSLT apesta. Su solución es elegante, pero seguramente no deberíamos elaborar rutinas de formateo de fechas a mano. – Ryan

+0

@Ryan: Estoy de acuerdo y XSLT 2 tiene un soporte mucho mejor para el manejo de fechas. Desafortunadamente, hay un soporte muy delgado en la base instalada de navegadores HTML, incluso ahora. – AnthonyWJones

+2

@AnthonyWJones: Es una exageración seria, XSLT 2.0 es muy delgado fuera de los lenguajes dinámicos. La mayoría de los cuales son Java y algunos .NET. No tenemos libXSLT para XSLT 2.0, que de lo contrario llevaría XSLT a un puñado de navegadores. Una vez que exista una biblioteca FOSS y eficiente C/C++ XSLT 2.0, con dependencias multiplataforma razonablemente mínimas, veremos compatibilidad con el navegador. – TechZilla

25

El formato de fecha no es fácil en XSLT 1.0. Probablemente la forma más elegante es escribir una función de extensión XSLT corta en C# para el formato de fecha. He aquí un ejemplo:

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

Con este documento de entrada

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

obtendrá

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

La función de formateo de la fecha toma un valor de fecha como cadena y un formato como se describe en DateTime.ToString Method . El uso de la estructura DateTime de .NET le permite analizar valores de fecha y hora de XSD arbitrarios (incluidos los especificadores de zona horaria), el cálculo de zona horaria y la salida localizada de forma gratuita.

Sin embargo, tenga en cuenta que hay un caveat (http://support.microsoft.com/kb/316775) con extensiones de script msxml: cada vez que carga el XSLT se genera dinámicamente un conjunto que contiene el código del script y se carga en la memoria. Debido al diseño del tiempo de ejecución de .NET, este ensamblaje no se puede descargar. Es por eso que debe asegurarse de que su XSLT solo se cargue una vez (y luego se almacena en caché para su posterior reutilización). Esto es especialmente importante cuando se ejecuta dentro de IIS.

+1

¡Sí, eso es casi idéntico al método que uso! – Cerebrus

+1

Simplemente curiosidad por la votación negativa: ¿Hay alguna razón técnica? ¿O simplemente desagrado personal por el enfoque? –

+0

Bajé la votación porque msxsl: script no es necesario (consulte la publicación de AnthonyW, que es la solución más elegante) y tiene serias desventajas: http://www.tkachenko.com/blog/archives/000620.html. Los objetos de extensión XSLT son mucho más preferibles para crear funciones XSLT personalizadas en .NET pruébelo :) –

9

John Workman analiza este problema detenidamente y ofrece varias soluciones en este discussion[1] en su blog. Básicamente, analiza los componentes de fecha individuales y recombínalos en el orden que desees. Para su caso, una versión pura XSLT 1.0+ sería:

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

Otro formato (reemplaza la sección de formato europeo):

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

Usted puede recombinar los elementos en cualquier forma que elija.

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

+1

Me gustaría hacerte un comentario agradable aquí. Tu código me salvó un terrible dolor de cabeza. – espais

3

corrección a cargo de Roy: el día de la función siempre obtendrá el valor de mes.Utiliza el siguiente:

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

+0

He solucionado el error. Gracias. – rivy

3

Gracias, este post ha ayudado mucho.

Estaba transformando una fuente RSS que usa el formato de fecha siguiente: lun, 04 de abril de 2011 23:18:00 -0700. Aquí está la plantilla con nombre que utilicé para analizarlo.

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

disculpas por sus comentarios sobre este viejo hilo, pero para los demás encontrando como yo también se puede usar javascript si está utilizando un transformador MS:

declarar la "msxsl" espacio de nombres:

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

Declara un espacio de nombres para su guión:

xmlns:js="urn:custom-javascript" 

(Opcional) Omite º e prefijos de la salida:

exclude-result-prefixes="msxsl js" 

por lo que terminan con una declaración XSL como esto:

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

Escribir el código JavaScript en el msxsl: Elemento de la escritura:

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

Llame a su Función JavaScript (usando la sintaxis XPath '.' Que denota 'este nodo'):

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

NB: A partir de la redacción, no parece haber una forma (xsl) de incluir archivos js externos (ej. biblioteca jquery). Esto podría hacerse analizando el lado del servidor de archivos xsl antes de la transformación y agregando el contenido del archivo js como una cadena en una sección CDATA. Comencé a tomar esta ruta yo mismo, pero concluí que si necesita este nivel de funcionalidad, podría estar mejor ubicado en una parte diferente de la tubería.

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

Cuestiones relacionadas