2012-05-21 1 views
2

У меня есть XML-поток событий, с датами, с которыми мне хотелось бы взаимодействовать.Расширение диапазонов дат-времени в XSLT 1.0

Источник 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], с другой стороны, охватывает два дня. Вот что я хотел бы сделать:

  1. Для событий, которые находятся в один день, оставьте только даты и просто преобразуйте эти атрибуты в дочерние элементы.
  2. Для событий, которые охватывают несколько дней, я хочу создать несколько элементов <event>, которые (а) соответствуют общему периоду времени и (б), когда это необходимо, охватывают весь день.

Итак, мой идеал 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> (один от стартового дня и до 23:59:59 по этой дате и один с 00:00:00 по окончанию до окончания datetime).

Заключительные соображения:

  • Это должно быть достигнуто в XSLT 1.0.

  • Я не против использования функций даты EXSLT - однако, если их можно избежать, это было бы предпочтительнее.

Очистить как грязь? Как всегда, спасибо за вашу помощь. :)

ответ

4

Ниже приведено решение 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 бы проще ....

+0

Я буду проверить t его выход, когда я возвращаюсь домой. Я согласен - EXSLT будет проще. : - \ Ухаживать за этим? ;) – ABach

+0

К сожалению, у меня нет EXSLT! Возможно, кто-то другой может принять вызов :) –

+0

Понял. Во всяком случае, я ценю ваш ответ.Держать крепко. :) – ABach