我在XML文件的字段中有一个日期值,格式为:
<Date value="4/1/2013 5:13:41 PM"/>
我想将其转换为标准的XSD格式:
2013-04-01T17:13:41.000Z
我如何在XSL转换中执行此操作?我可以使用1.0和2.0样式表版本。
答案 0 :(得分:5)
所以......我很无聊,之前没有和xsl:analyze-string玩过。这是一个基于正则表达式的解决方案:
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" version="2.0">
<xsl:template match="/item/date">
<xsl:analyze-string select="@value" regex="([0-9]+)/([0-9]+)/([0-9]+) ([0-9]+):([0-9]+):([0-9]+) (PM|AM)">
<xsl:matching-substring>
<xsl:variable name="month" select="number(regex-group(1))"/>
<xsl:variable name="day" select="number(regex-group(2))"/>
<xsl:variable name="year" select="number(regex-group(3))"/>
<xsl:variable name="hours">
<xsl:choose>
<xsl:when test="regex-group(7) = 'PM'">
<xsl:value-of select="12 + number(regex-group(4))"/>
</xsl:when>
<xsl:otherwise><xsl:value-of select="number(regex-group(4))"/></xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="minutes" select="number(regex-group(5))"/>
<xsl:variable name="seconds" select="number(regex-group(6))"/>
<xsl:variable name="dateTime" select="xs:dateTime( concat($year, '-', format-number($month, '00'), '-', format-number($day, '00'), 'T', format-number($hours, '00'), ':', format-number($minutes, '00'), ':', format-number($seconds, '00'), 'Z') )" />
<reformattedDate>
<xsl:value-of select="$dateTime"/>
</reformattedDate>
</xsl:matching-substring>
</xsl:analyze-string>
</xsl:template>
</xsl:stylesheet>
我针对像这样的测试xml文件运行了这个:
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<item>
<date value="4/1/2013 5:13:41 PM"/>
</item>
输出是这样的:
<?xml version="1.0" encoding="UTF-8"?>
<reformattedDate xmlns:xs="http://www.w3.org/2001/XMLSchema">2013-04-01T17:13:41Z</reformattedDate>
如果您想按照建议的那样更精确地格式化输出,可以使用format-date function。
答案 1 :(得分:4)
这是一个XSLT 1.0版本,使用substring-before
和substring-after
。
感谢adhocgeek
提供XML输入。
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/item">
<xsl:copy>
<xsl:apply-templates select="date"/>
</xsl:copy>
</xsl:template>
<xsl:template match="date">
<xsl:copy>
<xsl:variable name="date" select="substring-before(@value, ' ')"/>
<xsl:variable name="M" select="substring-before($date, '/')"/>
<xsl:variable name="D-Y" select="substring-after($date, '/')"/>
<xsl:variable name="D" select="substring-before($D-Y, '/')"/>
<xsl:variable name="Y" select="substring-after($D-Y, '/')"/>
<xsl:variable name="time-ampm" select="substring-after(@value, ' ')"/>
<xsl:variable name="time" select="substring-before($time-ampm, ' ')"/>
<xsl:variable name="ampm" select="substring-after($time-ampm, ' ')"/>
<xsl:variable name="h" select="substring-before($time, ':')"/>
<xsl:variable name="m-s" select="substring-after($time, ':')"/>
<xsl:variable name="m" select="substring-before($m-s, ':')"/>
<xsl:variable name="s" select="substring-after($m-s, ':')"/>
<xsl:variable name="hh">
<xsl:choose>
<xsl:when test="$ampm = 'PM'">
<xsl:value-of select="format-number($h + 12, '00')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="format-number($h, '00')"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:value-of select="concat($Y, '-', $M, '-', $D, 'T', $hh, ':', $m, ':', $s)"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
<强> XML 强>
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<item>
<date value="4/1/2013 5:13:41 PM"/>
</item>
<强>输出强>
<?xml version="1.0" encoding="utf-8"?>
<item>
<date>2013-4-1T05:13:41</date>
</item>
答案 2 :(得分:2)
看看ESXLT。许多XSL实现已经支持开箱即用的功能,并且如果您的不支持它们,它们会提供回退。
如果您具有完全兼容的实施,您可以这样做:
<?xml ...
xmlns.date="http://exslt.org/dates-and-times"
...
<xsl:variable name="xsdate" select="date:parse-date(Date/@value, 'M/d/yyyy h:mm:ss a')" />
<xsl:value-of select="$xsdate" />
我作弊并直接使用了date:parse
的结果。人们经常使用date:format
函数将日期格式化为特定格式。
老实说,我一直在努力从Apache Xalan中获取EXSLT的“后备”功能。 (Using non-core EXSLT date functions with Xalan Java)
IMO最好首先以xs:dateTime
格式设置日期,然后转换为某种本地化格式。您可以使用date:format
函数根据需要格式化日期,date:format
函数在XSLT处理器中享有更广泛的支持。
答案 3 :(得分:1)
使用XSLT 2.0,您可以使用字符串函数从xs:dateTime
中提取组件来构建Date/@value
值,然后您可以使用format-dateTime
http://www.w3.org/TR/xslt20/#format-date进行格式化。提取年,月,日等日期组件应该很简单,显然在您需要更多工作时要注意PM
或AM
12小时制。
答案 4 :(得分:0)
@ adhockgeek的回答几乎完美适合我。我只需要添加一个条件,这样如果当前值为12,则不会增加12小时.IE,12:15 PM!= 24:15 AM。
我从他的代码中创建了一个模板,可以在变换中重复调用:
<xsl:template name="FormatDate">
<xsl:param name="dt"/>
<xsl:analyze-string select="$dt" regex="([0-9]+)/([0-9]+)/([0-9]+) ([0-9]+):([0-9]+):([0-9]+) (PM|AM)">
<xsl:matching-substring>
<xsl:variable name="month" select="number(regex-group(1))"/>
<xsl:variable name="day" select="number(regex-group(2))"/>
<xsl:variable name="year" select="number(regex-group(3))"/>
<xsl:variable name="hours">
<xsl:choose>
<xsl:when test="regex-group(7) = 'PM' and regex-group(4) != '12'">
<xsl:value-of select="12 + number(regex-group(4))"/>
</xsl:when>
<xsl:otherwise><xsl:value-of select="number(regex-group(4))"/></xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="minutes" select="number(regex-group(5))"/>
<xsl:variable name="seconds" select="number(regex-group(6))"/>
<xsl:variable name="dateTime" select="xs:dateTime(concat($year, '-', format-number($month, '00'), '-', format-number($day, '00'), 'T', format-number($hours, '00'), ':', format-number($minutes, '00'), ':', format-number($seconds, '00')))" />
<xsl:value-of select="$dateTime"/>
</xsl:matching-substring>
</xsl:analyze-string>
</xsl:template>
答案 5 :(得分:0)
使用substring-before和substring-after工作的代码,但应添加更多检查: 12AM =&gt; 00和12PM =&gt; 12这样的事情:
<xsl:variable name="hh">
<xsl:choose>
<xsl:when test="$ampm = 'AM' and $h='12'">00</xsl:when>
<xsl:when test="$ampm = 'PM' and $h!='12'">
<xsl:value-of select="format-number($h + 12, '00')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="format-number($h, '00')"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>