在XSLT 1.0中扩展日期时间范围 [英] Expanding datetime ranges in XSLT 1.0

查看:112
本文介绍了在XSLT 1.0中扩展日期时间范围的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



源XML:

 <?xml version =1.0encoding =UTF-8?> 
< events>
< event>
<! - 各种元素 - >
< start_datetime value =2012-02-09 10:00:00/>
< end_datetime value =2012-02-09 11:00:00/>
<! - 各种元素 - >
< / event>
< event>
<! - 各种元素 - >
< start_datetime value =2012-02-09 10:00:00/>
< end_datetime value =2012-02-10 15:00:00/>
<! - 各种元素 - >
< / event>
<! - 其他事件 - >
< / events>

请注意, / events / event [1] / events / event [2] 这是我想要完成的:


  1. 对于同一天的事件,单独留下数据时间,并将这些属性转换为子元素

  2. 对于跨越多天的事件,我想创建多个< event> 元素,(a)匹配整体时间跨度(b)在适当的情况下,跨越一整天的时间。

所以,我理想的XSLT会产生: / p>

所需的XML:

  ?xml version =1.0encoding =UTF-8?> 
< events>
< event>
<! - 各种元素 - >
< start_datetime> 2012-02-09 10:00:00< / start_datetime>
< end_datetime> 2012-02-09 11:00:00< / end_datetime>
<! - 各种元素 - >
< / event>
< event>
<! - 各种元素 - >
< start_datetime> 2012-02-09 10:00:00< / start_datetime>
< end_datetime> 2012-02-09 23:59:59< / end_datetime>
<! - 各种元素 - >
< / event>
< event>
<! - 各种元素 - >
< start_datetime> 2012-02-10 00:00:00< / start_datetime>
< end_datetime> 2012-02-10 15:00:00< / end_datetime>
<! - 各种元素 - >
< / event>
<! - 其他事件 - >
< / events>注意我的规则如何满足:


>

  • 由于 / events / event [1] 在同一天发生,我们将它独占一个(除了将属性值更改为简单的任务子元素)。

  • / events / event [2] 跨越两天,这意味着需要两个 < event> 阻止(一个从起始日期时间到那天的11:59:59 pm,一个从结束日期的00:00:00到结束日期时间)。



  • 最终注意事项:




    • 这需要在XSLT 1.0中完成。


    • 我不反对使用EXSLT的日期功能 - 但是,如果可以避免,更好。




    一如以往,谢谢你的帮助。 :)

    解决方案

    这是一个XSLT 1.0解决方案,它不使用EXSLT日期功能,而是使用命名模板添加一个给定日期,使用字符串操作函数来从日期字符串额外的年,月和日日期

     < ; xsl:stylesheet version =1.0xmlns:xsl =http://www.w3.org/1999/XSL/Transform> 
    < xsl:output method =xmlindent =yes/>

    < xsl:template match =@ * | node()>
    < xsl:copy>
    < xsl:apply-templates select =@ * | node()/>
    < / xsl:copy>
    < / xsl:template>

    < xsl:template match =eventname =event>
    < xsl:param name =start_datetimeselect =start_datetime / @ value/>
    < xsl:variable name =end_datetimeselect =end_datetime / @ value/>
    < event>
    < xsl:apply-templates select =start_datetime / prior-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:否则>
    < xsl:value-of select =concat(substring($ start_datetime,1,10),'23:59:59')/>
    < / xsl:否则>
    < / 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 =dateselect =$ 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 =yearselect =number(substring($ date,1,4))/>
    < xsl:variable name =monthselect =number(substring($ date,6,2))/>
    < xsl:variable name =dayselect =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:否> 28< / xsl:否>
    < / xsl:choose>
    < / xsl:when>
    < xsl:when test =$ month = 4 or $ month = 6 or $ month = 9 or $ month = 11> 30< / xsl:when>
    < xsl:else> 31< / xsl:否>
    < / 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:否则>
    < xsl:value-of select =concat($ year,' - ',format-number($ month + 1,'00'),'-01 00:00:00')/& ;
    < / xsl:否则>
    < / xsl:choose>
    < / xsl:template>
    < / xsl:stylesheet>

    当应用于您的示例XML时,输出以下内容

     < events> 
    < event>
    <! - 各种元素 - >
    < start_datetime> 2012-02-09 10:00:00< / start_datetime>
    < end_datetime> 2012-02-09 11:00:00< / end_datetime>
    <! - 各种元素 - >
    < / event>
    < event>
    <! - 各种元素 - >
    < start_datetime> 2012-02-09 10:00:00< / start_datetime>
    < end_datetime> 2012-02-09 23:59:59< / end_datetime>
    <! - 各种元素 - >
    < / event>
    < event>
    <! - 各种元素 - >
    < start_datetime> 2012-02-10 00:00:00< / start_datetime>
    < end_datetime> 2012-02-10 15:00:00< / end_datetime>
    <! - 各种元素 - >
    < / event>
    <! - 其他事件 - >
    < / events>

    我相信你会同意使用EXSLT会更简单....


    I have an XML feed of events whose dates I would like to interact with.

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

    Notice that /events/event[1] is an event that starts and ends on the same day; /events/event[2], on the other hand, spans two days. Here's what I would like to accomplish:

    1. For events that are on the same day, leave the datetimes alone and merely transform those attributes into child elements.
    2. For events that span multiple days, I want to create multiple <event> elements that (a) match the overall span of time and (b) where appropriate, span a full day's worth of time.

    So, my ideal XSLT would produce:

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

    Notice how my rules are met:

    • Because /events/event[1] occurs over the same day, we leave it alone (other than the trivial task of changing attribute values into child elements).
    • /events/event[2] spans two days, which means it needs two <event> blocks (one from the starting datetime to 11:59:59pm on that date and one from 00:00:00 on the ending date to the ending datetime).

    Final Considerations:

    • This needs to be accomplished in XSLT 1.0.

    • I am not opposed to using EXSLT's date functions - however, if they can be avoided, that would be preferable.

    Clear as mud? As always, thanks for your help. :)

    解决方案

    Here is an XSLT 1.0 solution, that doesn't use EXSLT date functions, but which makes use of a named template to add one to a given date, using string manipulation functions to extra the year, month and day from a date string

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

    When applied to your sample XML, the following is output

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

    I am sure you would agree using EXSLT would be simpler....

    这篇关于在XSLT 1.0中扩展日期时间范围的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆