转换和排序不同的日期格式
Transform and sort different date formats
我的任务是使用不同的日期格式转换生成的 XML 文件
作为排序标准。作为 XSLT 的新手,我想知道是否可以使用单个转换来统一日期格式和排序。
来源 XML 的示例在这里:
<?xml version="1.0"?>
<summary>
<incoming>
<delivery incDate="2013-11-08"/>
</incoming>
<outgoing>
<delivery outDate="20131108"/>
</outgoing>
<repairs>
<repair repairDate="2013-11-08 11:25:34"/>
</repairs>
</summary>
这就是我想要实现的目标:
<?xml version="1.0"?>
<summary>
<actions>
<action type="incoming" dateTime="2013-11-08 00:00:00"/>
<action type="repair" dateTime="2013-11-08 11:25:34"/>
<action type="outgoing" dateTime="2013-11-08 23:59:59"/>
</actions>
</summary>
我做了什么?
- 统一所有日期格式。
- 在
<incoming>
的所有孩子上附加时间 00:00:00。
- 在
<outgoing>
的所有孩子上附加时间 23:59:59。
- 添加名称为 parent 的属性。
- 按日期排序输出。
在 XSLT 2.0 中,这非常简单,因为您可以使用两遍方法,首先生成所需的输出,然后对它们进行排序:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" indent="yes" />
<xsl:template match="/">
<summary>
<actions>
<xsl:perform-sort>
<xsl:sort select="@dateTime" />
<xsl:apply-templates select="summary/*/*" />
</xsl:perform-sort>
</actions>
</summary>
</xsl:template>
<xsl:template match="incoming/delivery">
<action type="incoming" dateTime="{@incDate} 00:00:00"/>
</xsl:template>
<xsl:template match="outgoing/delivery">
<action type="outgoing" dateTime="{substring(@outDate, 1, 4)}-{substring(@outDate, 5, 2)}-{substring(@outDate, 7, 2)} 23:59:59"/>
</xsl:template>
<xsl:template match="repairs/repair">
<action type="repair" dateTime="{@repairDate}"/>
</xsl:template>
</xsl:stylesheet>
在这里,我们使用 apply-templates
和 然后 为每个输入元素生成输出,然后使用 XPath 表达式 perform-sort
对这些生成的元素进行排序( @dateTime
) 相对于生成的 XML 而不是原始的
如果您限于 1.0,则这不是一个选项,因为您只能根据输入 XML 中的内容进行排序,而不是生成的输出。所以我们需要提出一个 XPath 1.0 表达式,它可以处理三种日期格式中的任何一种,并生成合适的排序键
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes" />
<xsl:template match="/">
<summary>
<actions>
<xsl:apply-templates select="summary/*/*">
<xsl:sort select="
translate(
concat(
@incDate, @outDate, @repairDate,
substring('000000', 6*not(@incDate) + 1),
substring('235959', 6*not(@outDate) + 1)
),
'-: ',
''
)" />
</xsl:apply-templates>
</actions>
</summary>
</xsl:template>
<!-- the other three templates are unchanged -->
这使用了很多技巧,最著名的是
substring('000000', 6*not(@incDate) + 1)
这取决于很多事情:
not()
的参数被视为布尔值。
- 当您将节点集视为布尔值时,空集为假,非空集为真
- 将布尔值转换为数字给出 1 表示真,0 表示假
因此,如果目标节点具有 incDate
属性,则效果是 return 字符串 000000
,如果没有,则为空字符串。最后的 concat
构建一个字符串,对于 incDate
看起来像 YYYY-MM-DD000000
,对于 outDate
看起来像 YYYYMMDD235959
,对于 repairDate
,translate
去除所有空格、连字符和冒号,将这三者带入可以按字典顺序进行比较的通用格式。
我的任务是使用不同的日期格式转换生成的 XML 文件 作为排序标准。作为 XSLT 的新手,我想知道是否可以使用单个转换来统一日期格式和排序。
来源 XML 的示例在这里:
<?xml version="1.0"?>
<summary>
<incoming>
<delivery incDate="2013-11-08"/>
</incoming>
<outgoing>
<delivery outDate="20131108"/>
</outgoing>
<repairs>
<repair repairDate="2013-11-08 11:25:34"/>
</repairs>
</summary>
这就是我想要实现的目标:
<?xml version="1.0"?>
<summary>
<actions>
<action type="incoming" dateTime="2013-11-08 00:00:00"/>
<action type="repair" dateTime="2013-11-08 11:25:34"/>
<action type="outgoing" dateTime="2013-11-08 23:59:59"/>
</actions>
</summary>
我做了什么?
- 统一所有日期格式。
- 在
<incoming>
的所有孩子上附加时间 00:00:00。 - 在
<outgoing>
的所有孩子上附加时间 23:59:59。 - 添加名称为 parent 的属性。
- 按日期排序输出。
在 XSLT 2.0 中,这非常简单,因为您可以使用两遍方法,首先生成所需的输出,然后对它们进行排序:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" indent="yes" />
<xsl:template match="/">
<summary>
<actions>
<xsl:perform-sort>
<xsl:sort select="@dateTime" />
<xsl:apply-templates select="summary/*/*" />
</xsl:perform-sort>
</actions>
</summary>
</xsl:template>
<xsl:template match="incoming/delivery">
<action type="incoming" dateTime="{@incDate} 00:00:00"/>
</xsl:template>
<xsl:template match="outgoing/delivery">
<action type="outgoing" dateTime="{substring(@outDate, 1, 4)}-{substring(@outDate, 5, 2)}-{substring(@outDate, 7, 2)} 23:59:59"/>
</xsl:template>
<xsl:template match="repairs/repair">
<action type="repair" dateTime="{@repairDate}"/>
</xsl:template>
</xsl:stylesheet>
在这里,我们使用 apply-templates
和 然后 为每个输入元素生成输出,然后使用 XPath 表达式 perform-sort
对这些生成的元素进行排序( @dateTime
) 相对于生成的 XML 而不是原始的
如果您限于 1.0,则这不是一个选项,因为您只能根据输入 XML 中的内容进行排序,而不是生成的输出。所以我们需要提出一个 XPath 1.0 表达式,它可以处理三种日期格式中的任何一种,并生成合适的排序键
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes" />
<xsl:template match="/">
<summary>
<actions>
<xsl:apply-templates select="summary/*/*">
<xsl:sort select="
translate(
concat(
@incDate, @outDate, @repairDate,
substring('000000', 6*not(@incDate) + 1),
substring('235959', 6*not(@outDate) + 1)
),
'-: ',
''
)" />
</xsl:apply-templates>
</actions>
</summary>
</xsl:template>
<!-- the other three templates are unchanged -->
这使用了很多技巧,最著名的是
substring('000000', 6*not(@incDate) + 1)
这取决于很多事情:
not()
的参数被视为布尔值。- 当您将节点集视为布尔值时,空集为假,非空集为真
- 将布尔值转换为数字给出 1 表示真,0 表示假
因此,如果目标节点具有 incDate
属性,则效果是 return 字符串 000000
,如果没有,则为空字符串。最后的 concat
构建一个字符串,对于 incDate
看起来像 YYYY-MM-DD000000
,对于 outDate
看起来像 YYYYMMDD235959
,对于 repairDate
,translate
去除所有空格、连字符和冒号,将这三者带入可以按字典顺序进行比较的通用格式。