В XSLT 1.0 встроенных средств нет. В XSLT 2.0, насколько я понимаю,
можно выкрутится встроенными средствами, но мне требуется XSLT 1.0.
Можно подключить JavaScript и написать скрипт для инкремента даты. Однако, как оказалось, можно обойтись и без JavaScript'а.
Вот здесь приведены исходные коды двух функций, позволяющих преобразовать дату в количество дней, прошедших с 31-декабря 0-ого года, и обратно. Если у нас в распоряжении есть такие функции, то выполнить инкремент даты не составит проблем:
int date; //количество дней itod(&date, 2009, 2, 3); //получаем количество дней для даты 3.02.2009 int y, m, d; dtoi(date+1, &y, &m, &d); //получаем год, месяц, число для 4.02.2009.
Приложение на С выглядит так:
void dtoi (int date, int &year, int &month, int &day) { // the date specified as the number of days elapsed since //31 Dec of year 0. So 1 Jan 0001 is 1. int Z = date + 306; int H = 100*Z - 25; int A = H/3652425; int B = A - A/4; year = (100*B + H) / 36525; int C = B + Z - 365*year - year / 4; month = (5*C + 456) / 153; day = C - (153*month - 457) / 5; if (month > 12) { year += 1; month -= 12; } } int itod (int y, int m, int d) { if (m < 3) { m += 12; y -= 1; } return d + (153*m - 457) / 5 + 365*y + y/4 - y/100 + y/400 - 306; } int _tmain(int argc, _TCHAR* argv[]) { int date = itod(2009, 12, 31); int y, m, d; dtoi(date+1, y, m, d); }
Перевел код на XSLT. Получилось следующее:
<xsl:template name="date_to_int"> <xsl:param name="y" /> <xsl:param name="m" /> <xsl:param name="d" /> <xsl:choose> <xsl:when test="number($m) < 3"> <xsl:call-template name="date_to_int_auxilary"> <xsl:with-param name="y" select="number($y)-1"/> <xsl:with-param name="m" select="number($m)+12"/> <xsl:with-param name="d" select="$d"/> </xsl:call-template> </xsl:when> <xsl:otherwise> <xsl:call-template name="date_to_int_auxilary"> <xsl:with-param name="y" select="$y"/> <xsl:with-param name="m" select="$m"/> <xsl:with-param name="d" select="$d"/> </xsl:call-template> </xsl:otherwise> </xsl:choose> </xsl:template> <xsl:template name="date_to_int_auxilary"> <xsl:param name="y" /> <xsl:param name="m" /> <xsl:param name="d" /> <xsl:value-of select="number($d) + floor((153.0*number($m) - 457.0) div 5.0) + 365*number($y) + floor(number($y) div 4 ) - floor(number($y) div 100) + floor(number($y) div 400) - 306"/> </xsl:template> <!-- Convert number of days to date (year, month, day - required part of the date is selected by 'required_value' parameter --> <xsl:template name="int_to_date"> <xsl:param name="g"/> <xsl:param name="required_value" select="'year'"/> <!-- 'year' or 'month' or 'day'--> <xsl:variable name="Z" select="floor(number($g) + 306)"/> <xsl:variable name="H" select="floor(100*number($Z) - 25)"/> <xsl:variable name="A" select="floor(number($H) div 3652425)"/> <xsl:variable name="B" select="floor(number($A) - number($A) div 4)"/> <xsl:variable name="year" select="floor((number($B)*100 + number($H)) div 36525)"/> <xsl:variable name="C" select="floor(-365.0*number($year) + number($B) + number($Z)- floor(number($year) div 4))"/> <xsl:variable name="month" select="floor((number($C)*5 + 456) div 153)"/> <xsl:variable name="day" select="number($C) - floor(( floor(153*number($month)) - 457) div 5)"/> <xsl:choose> <xsl:when test="number($month) > 12"> <xsl:call-template name="int_to_date_helper"> <xsl:with-param name="year" select="number($year)+1"/> <xsl:with-param name="month" select="number($month)-12"/> <xsl:with-param name="day" select="number($day)"/> <xsl:with-param name="required_value" select="$required_value"/> </xsl:call-template> </xsl:when> <xsl:otherwise> <xsl:call-template name="int_to_date_helper"> <xsl:with-param name="year" select="number($year)"/> <xsl:with-param name="month" select="number($month)"/> <xsl:with-param name="day" select="number($day)"/> <xsl:with-param name="required_value" select="$required_value"/> </xsl:call-template> </xsl:otherwise> </xsl:choose> </xsl:template> <xsl:template name="int_to_date_helper"> <xsl:param name="year"/> <xsl:param name="month"/> <xsl:param name="day"/> <xsl:param name="required_value"/> <!-- 'year' or 'month' or 'day'--> <xsl:choose> <xsl:when test="$required_value='year'"> <xsl:value-of select="round($year)"/> </xsl:when> <xsl:when test="$required_value='month'"> <xsl:value-of select="round($month)"/> </xsl:when> <xsl:when test="$required_value='day'"> <xsl:value-of select="round($day)"/> </xsl:when> </xsl:choose> </xsl:template>
Функция int_to_date соответствует C-шной функции itod, функция date_to_int - функции dtoi. Функция date_to_int принимает два параметра - количество дней и название требуемой части даты - 'year', 'month' или 'day' (передавать прямо в апострофах). Таким образом, если вы хотите напечатать дату в виде "Год.Месяц.День", то функцию date_to_int придется вызвать трижды - один раз, чтобы получить год, второй - месяц, третий - день. Впрочем, совсем несложно изменить шаблон так, чтобы функция возвращала дату целиком, в виде строки в подходящем формате.
Полный текст тестового преобразования с примером вызова можно взять здесь.
P.s. самой заковыристой частью трансляции кода оказалось правильное округление чисел в алгоритме. Дело в том, что в алгоритме используются целые числа и во всех расчетах нужно использовать именно целые, а не вещественные числа. Отсюда многочисленные floor в преобразовании.
Комментариев нет:
Отправить комментарий