我有一个 XML 源,其中包含我想与之交互的事件日期。
源 XML:
<?xml version="1.0" encoding="UTF-8"?>
<events>
<event>
<!-- various elements -->
<start_datetime value="2012-02-09 10:00:00"/>
<end_datetime value="2012-02-09 11:00:00"/>
<!-- various elements -->
</event>
<event>
<!-- various elements -->
<start_datetime value="2012-02-09 10:00:00"/>
<end_datetime value="2012-02-10 15:00:00"/>
<!-- various elements -->
</event>
<!-- other events -->
</events>
请注意,/events/event[1]
是在同一天开始和结束的事件; 另一方面,/events/event[2]
跨越了两天。 以下是我想完成的:
- 对于同一天的事件,请保留日期时间,仅将这些属性转换为子元素。
- 对于跨越多天的事件,我想创建多个
<event>
元素,这些元素 (a( 匹配整体时间跨度,(b( 在适当的情况下,跨越一整天的时间。
因此,我理想的 XSLT 将产生:
所需的 XML:
<?xml version="1.0" encoding="UTF-8"?>
<events>
<event>
<!-- various elements -->
<start_datetime>2012-02-09 10:00:00</start_datetime>
<end_datetime>2012-02-09 11:00:00</end_datetime>
<!-- various elements -->
</event>
<event>
<!-- various elements -->
<start_datetime>2012-02-09 10:00:00</start_datetime>
<end_datetime>2012-02-09 23:59:59</end_datetime>
<!-- various elements -->
</event>
<event>
<!-- various elements -->
<start_datetime>2012-02-10 00:00:00</start_datetime>
<end_datetime>2012-02-10 15:00:00</end_datetime>
<!-- various elements -->
</event>
<!-- other events -->
</events>
请注意我的规则是如何满足的:
- 由于
/events/event[1]
在同一天发生,因此我们将其保留(除了将属性值更改为子元素的琐碎任务(。 -
/events/event[2]
跨越两天,这意味着它需要两个<event>
块(一个从开始日期时间到该日期的晚上 11:59:59,另一个从结束日期的 00:00:00 到结束日期时间(。
最后的考虑:
这需要在 XSLT 1.0 中完成。
我不反对使用 EXSLT 的日期函数 - 但是,如果可以避免它们,那将是可取的。
清澈如泥? 与往常一样,感谢您的帮助。:)
这是一个 XSLT 1.0 解决方案,它不使用 EXSLT 日期函数,但它使用命名模板将一个添加到给定日期,使用字符串操作函数从日期字符串中额外增加年、月和日
。<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="event" name="event">
<xsl:param name="start_datetime" select="start_datetime/@value"/>
<xsl:variable name="end_datetime" select="end_datetime/@value"/>
<event>
<xsl:apply-templates select="start_datetime/preceding-sibling::node()"/>
<start_datetime>
<xsl:value-of select="$start_datetime"/>
</start_datetime>
<end_datetime>
<xsl:choose>
<xsl:when test="substring($start_datetime, 1, 10) = substring($end_datetime ,1, 10)">
<xsl:value-of select="$end_datetime"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat(substring($start_datetime, 1, 10), ' 23:59:59')"/>
</xsl:otherwise>
</xsl:choose>
</end_datetime>
<xsl:apply-templates select="end_datetime/following-sibling::node()"/>
</event>
<xsl:if test="substring($start_datetime, 1, 10) != substring($end_datetime ,1, 10)">
<xsl:call-template name="event">
<xsl:with-param name="start_datetime">
<xsl:call-template name="addOneToDate">
<xsl:with-param name="date" select="$start_datetime"/>
</xsl:call-template>
</xsl:with-param>
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template name="addOneToDate">
<xsl:param name="date"/>
<xsl:variable name="year" select="number(substring($date, 1, 4))"/>
<xsl:variable name="month" select="number(substring($date, 6, 2))"/>
<xsl:variable name="day" select="number(substring($date, 9, 2))"/>
<xsl:variable name="daysInMonth">
<xsl:choose>
<xsl:when test="$month = 2">
<xsl:choose>
<xsl:when test="($year div 4 = 0 and $year div 100 != 0) or ($year div 400 = 0)">29</xsl:when>
<xsl:otherwise>28</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:when test="$month = 4 or $month = 6 or $month = 9 or $month = 11">30</xsl:when>
<xsl:otherwise>31</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:choose>
<xsl:when test="$day != $daysInMonth">
<xsl:value-of select="concat($year, '-', format-number($month, '00'), '-', format-number($day + 1, '00'), ' 00:00:00')"/>
</xsl:when>
<xsl:when test="$month = 12">
<xsl:value-of select="concat($year + 1, '-01-01 00:00:00')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat($year, '-', format-number($month + 1, '00'), '-01 00:00:00')"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
应用于示例 XML 时,输出如下
<events>
<event>
<!-- various elements -->
<start_datetime>2012-02-09 10:00:00</start_datetime>
<end_datetime>2012-02-09 11:00:00</end_datetime>
<!-- various elements -->
</event>
<event>
<!-- various elements -->
<start_datetime>2012-02-09 10:00:00</start_datetime>
<end_datetime>2012-02-09 23:59:59</end_datetime>
<!-- various elements -->
</event>
<event>
<!-- various elements -->
<start_datetime>2012-02-10 00:00:00</start_datetime>
<end_datetime>2012-02-10 15:00:00</end_datetime>
<!-- various elements -->
</event>
<!-- other events -->
</events>
我相信你会同意使用 EXSLT 会更简单......