如何用XSLT实现日期偏移转换?XSLT1.0与2.0方案对比
问题
需要对一份XML进行转换,修改其中的日期字段:将所有<start>节点的值设为当前DateTime,<end>节点的值设为次日日期。
源XML如下:
<?xml version="1.0" encoding="UTF-8"?> <Publication_MarketDocument xmlns="urn:iec62325.351:tc57wg16:451-3:publicationdocument:7:0"> <period.timeInterval> <start>2022-09-27T22:00Z</start> <end>2022-09-29T22:00Z</end> </period.timeInterval> <TimeSeries> <Period> <timeInterval> <start>2022-09-27T22:00Z</start> <end>2022-09-28T22:00Z</end> </timeInterval> <resolution>PT60M</resolution> <Point> <position>1</position> <price.amount>323.70</price.amount> </Point> <Point> <position>2</position> <price.amount>309.91</price.amount> </Point> </Period> </TimeSeries> </Publication_MarketDocument>
已编写XSLT 2.0代码实现需求:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:xs="http://www.w3.org/2001/XMLSchema" xpath-default-namespace="urn:iec62325.351:tc57wg16:451-3:publicationdocument:7:0"> <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> <xsl:strip-space elements="*"/> <!-- transform --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <xsl:variable name="dateNow" select="fn:format-dateTime(fn:current-dateTime(), '[Y]-[M]-[D]T[H]:[m]Z')"/> <xsl:variable name="dateTomorrow" select="fn:format-dateTime(fn:current-dateTime() + xs:dayTimeDuration('P1D'), '[Y]-[M]-[D]T[H]:[m]Z')"/> <xsl:template match="start/text()"> <xsl:value-of select="$dateNow"/> </xsl:template> <xsl:template match="end/text()"> <xsl:value-of select="$dateTomorrow"/> </xsl:template> </xsl:stylesheet>
最初因命名空间问题转换失败,设置默认命名空间后可正常运行,但该代码基于XSLT 2.0,无法被XSLT 1.0处理器支持。目标环境为Linux,当前使用依赖JRE的Saxon处理器可得到正确结果,但JRE对自动化测试系统部署过于臃肿,询问能否仅用XSLT 1.0实现该日期偏移转换需求?
解决方案
可以用XSLT 1.0实现,不过XSLT 1.0本身没有内置日期处理函数,需借助处理器扩展或外部传入日期参数两种方式,具体实现如下:
方式一:使用libxslt的EXSLT日期扩展(Linux常用)
Linux环境下主流的XSLT 1.0处理器libxslt支持EXSLT的date扩展函数,可直接获取当前时间并计算次日日期。
对应的XSLT 1.0代码:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:doc="urn:iec62325.351:tc57wg16:451-3:publicationdocument:7:0" xmlns:date="http://exslt.org/dates-and-times" exclude-result-prefixes="date doc"> <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> <xsl:strip-space elements="*"/> <!-- 身份模板:复制所有未被匹配的节点 --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <!-- 格式化当前时间为要求的UTC格式 --> <xsl:variable name="current-time" select="date:date-time()"/> <xsl:variable name="formatted-now"> <xsl:value-of select="concat( substring($current-time, 1, 4), '-', substring($current-time, 6, 2), '-', substring($current-time, 9, 2), 'T', substring($current-time, 12, 2), ':', substring($current-time, 15, 2), 'Z' )"/> </xsl:variable> <!-- 计算并格式化次日UTC时间 --> <xsl:variable name="tomorrow-time" select="date:add($current-time, 'P1D')"/> <xsl:variable name="formatted-tomorrow"> <xsl:value-of select="concat( substring($tomorrow-time, 1, 4), '-', substring($tomorrow-time, 6, 2), '-', substring($tomorrow-time, 9, 2), 'T', substring($tomorrow-time, 12, 2), ':', substring($tomorrow-time, 15, 2), 'Z' )"/> </xsl:variable> <!-- 替换所有<start>节点的文本 --> <xsl:template match="doc:start/text()"> <xsl:value-of select="$formatted-now"/> </xsl:template> <!-- 替换所有<end>节点的文本 --> <xsl:template match="doc:end/text()"> <xsl:value-of select="$formatted-tomorrow"/> </xsl:template> </xsl:stylesheet>
使用libxslt自带的xsltproc命令执行转换:
xsltproc transform.xsl input.xml > output.xml
方式二:外部传入日期参数(无扩展依赖)
如果无法使用扩展函数,可通过Shell脚本生成当前日期和次日日期,再传入XSLT处理器,避免在XSLT中处理日期计算。
对应的XSLT 1.0代码:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:doc="urn:iec62325.351:tc57wg16:451-3:publicationdocument:7:0" exclude-result-prefixes="doc"> <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> <xsl:strip-space elements="*"/> <!-- 定义外部传入的日期参数 --> <xsl:param name="current-date-time"/> <xsl:param name="tomorrow-date-time"/> <!-- 身份模板 --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <xsl:template match="doc:start/text()"> <xsl:value-of select="$current-date-time"/> </xsl:template> <xsl:template match="doc:end/text()"> <xsl:value-of select="$tomorrow-date-time"/> </xsl:template> </xsl:stylesheet>
用Shell脚本生成日期并调用xsltproc:
#!/bin/bash # 生成UTC格式的当前日期和次日日期 current=$(date -u +"%Y-%m-%dT%H:%MZ") tomorrow=$(date -u -d "+1 day" +"%Y-%m-%dT%H:%MZ") # 传入参数执行转换 xsltproc --stringparam current-date-time "$current" --stringparam tomorrow-date-time "$tomorrow" transform.xsl input.xml > output.xml
内容的提问来源于stack exchange,提问作者EricBDev
相关产品推荐
相关产品推荐

