XSLT 1.0: получить список дат между двумя датами с помощью XSLT

Мне нужно получить список дат между двумя датами - например. У меня есть дата начала 03302012 и дата окончания 05302012, и мне нужен вывод, например

03302012
03312012
04012012
04022012
...
05282012
05292012
05302012
  • Не стесняйтесь использовать свой формат даты - я сделаю трансформацию сам. Большое спасибо!

person Alyaksandr Stzhalkouski    schedule 09.04.2012    source источник
comment
привет, не забудьте принять ответ.   -  person InfantPro'Aravind'    schedule 17.05.2012


Ответы (2)


Вы можете сделать это, используя рекурсивный шаблон. Это не лучшее решение, так как это может привести к переполнению стека или ошибкам нехватки памяти (если указанный вами интервал дат достаточно велик), но это может быть отправной точкой.

Первое, что вам нужно для приведенного ниже примера, — это способ проверить сгенерированное значение и убедиться, что оно является допустимой датой (для этого вы можете найти несколько примеров в Интернете; я просто использовал пример из проекта с открытым исходным кодом и импортировал файл в пример, чтобы сделать его короче).

Затем идея состоит в том, чтобы сгенерировать даты, добавив день к предыдущему, а затем день к текущему и так далее. Если день переполняется, вы добавляете единицу к месяцу и начинаете снова с 1-го дня. Если месяц переполняется, вы делаете то же самое с годом и начинаете с 1-го месяца. Теоретически единственный, который никогда не переполняется, — это год (но вы ограничите это с конечным значением интервала).

Вы создаете дату и проверяете ее. Если он действителен и не достиг конца интервала, вы пытаетесь сгенерировать другой, добавив к нему дни (это то, что происходит в блоке X).

Когда вы получаете недопустимое значение, значит, что-то переполнилось. Это может быть только день или месяц (как я упоминал выше). Сначала я проверяю месяц (блок Y). Если это так, я начинаю с 1-го дня 1-го месяца, но на следующий год. Если это день переполнения (блок Z), то я начинаю с 1-го числа следующего месяца.

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:import href="http://www.getsymphony.com/download/xslt-utilities/source-code/54294/"/>
  <xsl:output method="xml" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />

  <xsl:variable name="startDate" select="'03302012'" />  <!-- MMddyyyy format -->
  <xsl:variable name="endDate" select="'05302012'" /> <!-- MMddyyyy format -->

  <xsl:template match="/">
    <values>
      <xsl:call-template name="GenerateList">
        <xsl:with-param name="day" select="number(substring($startDate, 3, 2))" />
        <xsl:with-param name="month" select="number(substring($startDate, 1, 2))" />
        <xsl:with-param name="year" select="number(substring($startDate, 5))" />
      </xsl:call-template>
    </values>
  </xsl:template>

  <xsl:template name="GenerateList">
    <xsl:param name="day" select="1" />
    <xsl:param name="month" select="1" />
    <xsl:param name="year" select="1" />

    <!-- 1 = valid, 0 = invalid according to the imported file -->
    <xsl:variable name="validationResult">
      <xsl:call-template name="date-is-valid">
        <xsl:with-param name="day" select="$day"/>
        <xsl:with-param name="month" select="$month"/>
        <xsl:with-param name="year" select="$year"/>
      </xsl:call-template>
    </xsl:variable>

    <xsl:choose>
      <xsl:when test="$validationResult = 0">

        <xsl:choose>
          <xsl:when test="$month &gt; 12">
            <!-- block Y -->
            <xsl:call-template name="GenerateList">
              <xsl:with-param name="day" select="1" />
              <xsl:with-param name="month" select="1" />
              <xsl:with-param name="year" select="$year + 1" />
            </xsl:call-template>
          </xsl:when>
          <xsl:otherwise>
            <!-- block Z --> 
            <xsl:call-template name="GenerateList">
              <xsl:with-param name="day" select="1" />
              <xsl:with-param name="month" select="$month + 1" />
              <xsl:with-param name="year" select="$year" />
            </xsl:call-template>
          </xsl:otherwise>
        </xsl:choose>

      </xsl:when>
      <xsl:otherwise>
        <!-- block X -->
        <!-- same MMddyyyy format as the interval values -->
        <xsl:variable name="currentDate" select="concat(format-number($month, '00'), format-number($day, '00'), $year)" />
        <value>
          <xsl:value-of select="$currentDate" />
        </value>
        <xsl:if test="not($currentDate = $endDate)">
          <xsl:call-template name="GenerateList">
            <xsl:with-param name="day" select="$day + 1" />
            <xsl:with-param name="month" select="$month" />
            <xsl:with-param name="year" select="$year" />
          </xsl:call-template>
        </xsl:if>

      </xsl:otherwise>
    </xsl:choose>

  </xsl:template>
</xsl:stylesheet>
person Bogdan    schedule 10.04.2012

К сожалению, сам XSLT 1.0 для таких задач неудобен, но его среда обычно удобна. Ниже приведены некоторые подходы, которые я использовал сам:

  1. Обычно самое простое решение — сделать такой список частью ввода =)

  2. Преобразование XSLT обычно является частью более крупного приложения с определенным процессором XSLT, что позволяет использовать специальные средства для его расширения. Вы можете написать функцию расширения (используя Java, Javascript, PHP, Python в зависимости от процессора), которая возвращает требуемый набор узлов. Другой, но похожий вариант — зарегистрировать «поток» (по крайней мере, с точки зрения PHP) и получить набор узлов, используя функцию document с URL-адресом, например app://Dates/listdates?start=a&end=b. Недостатком является то, что таблица стилей связана с приложением и не может разрабатываться отдельно.

  3. Большинство процессоров XSTL поддерживают расширения EXSLT. Вы можете вычислить количество дней между датами, используя расширения даты, сгенерировать строку длины, используя функцию padding из расширения строки, разделить строку на пустую строку, чтобы получить список токенов (необходимой длины) и выполнить итерацию по списку. используя функцию node-set и добавляя текущую позицию узла к первой дате, используя date-add.

  4. Используйте чистый XSLT и рекурсивные шаблоны, как предлагает Богдан.

person newtover    schedule 10.04.2012