Технология XSLT — страница 37 из 66

Мы уже познакомились с функцией языка XPath

string
, которая конвертирует свой аргумент в строку. Эта функция может преобразовать в строку и численное значение, но возможности ее при этом сильно ограничены.

К счастью, XSLT предоставляет мощные возможности для форматирования строкового представления чисел при помощи функции

format-number
и элемента
xsl:decimal-format
.

Функция format-number

Запись функции имеет следующий вид:

string format-number(number, string, string?)

Функция

format-number
принимает на вход три параметра. Первым параметром является число, которое необходимо преобразовать в строку, применив при этом форматирование. Вторым параметром является образец, в соответствии с которым будет форматироваться число. Третий параметр указывает название десятичного формата, который следует применять.

Образец форматирования в XSLT определяется точно так же, как в классе

DecimalFormat
языка Java. Для того чтобы читателю, не знакомому с Java, не пришлось изучать документацию этого языка, мы приведем полный синтаксис образцов форматирования. Продукции образца форматирования мы будем помечать номерами с префиксом
NF
, чтобы не путать их с другими продукциями.

Прежде всего, образец форматирования может состоять из двух частей: первая часть определяет форматирование положительного числа, вторая часть — отрицательного. Запишем это в виде EBNF-продукции:

[NF 1] NFPattern ::= NFSubpattern (NFSubpatternDelim NFSubpattern)?

Двум частям образца форматирования соответствуют нетерминалы

NFSubpattern
, которые разделены нетерминалом
NFSubpatternDelim
.

В случае если вторая часть образца форматирования опушена, отрицательные числа форматируются точно так же, как и положительные, но им предшествует префикс отрицательного числа (по умолчанию — знак "минус", "

-
").

Примеры

format-number(1234.567,'#.00;negative #.00') 
 '1234.57'

format-number(-1234.567,'#.00/negative #.00') 
 'negative 1234.57'

format-number(-1234.567,'#.00') 
 '-1234.57'

Каждая из частей образца форматирования состоит из префикса (

NFPrefix
), целой части (
NFInteger
), необязательной дробной части (
NFFractional
) и суффикса (
NFSuffix
).

[NF 2] NFSubpattern ::= NFPrefix NFinteger NFFractional? NFSuffix

Префикс или суффикс образца форматирования могут содержать символ процента. Если суффикс содержит символ процента, число должно быть умножено на

100
и выведено со знаком процента. Наличие символа процента в префиксе на форматирование не влияет.

Пример

format-number(0.45,'0.00%') 
 '45.00%'

format-number(0.45,'0.##%') 
 '45.00%'

format-number(0.45678,'%0.00') 
 '%0.46'

format-number(0.45678,'0.####%') 
 '45.678%'

Префикс задает строку, которая будет предшествовать числу, это может быть последовательность любых неформатирующих символов (

NFChar
) плюс символ процента (
NFPercent
). Аналогично, суффикс будет следовать за числом, и он тоже не может содержать форматирующих символов (за исключением символа процента).

[NF 3] NFPrefix ::= (NFChar NFPercent?)*

[NF 4] NFSuffix ::= (NFChar NFPercent?)*

Пример

Если мы хотим заключить наше число, к примеру, в квадратные скобки, мы должны будем включить в его образец форматирования префикс "

[
" и суффикс "
]
":

format-number(123456, '[#]') 
 '[123456]'

Нетерминал

NFinteger
определяет, как будет выглядеть целая часть числа. Он начинается несколькими символами
NFOptDigit
(по умолчанию "
#
"), показывающими позиции, в которых цифры необязательны, и состоит из символов
NFReqDigit
(по умолчанию "
0
"), показывающих позиции обязательных цифр, а также символа
NFGroupDelim
(по умолчанию "
,
"), показывающего позицию символа-разделителя групп цифр.

[NF 5] NFInteger ::= NFOptDigit*

                     (NFReqDigit* NFGroupDelim

                     | NFGroupDelim NFOptDigit*)?

                     NFReqDigit+

Примеры

format-number(1234.56,'#0000') 
 '1235'

format-number(1234.56,'00000') 
 '01235'

format-number(1234.56,'00,000') 
 '01,235'

format-number(1234.56,'000,00') 
 '0,12,35'

Замечание

Некоторые процессоры позволяют указывать несколько символов-разделителей. Однако даже в этом случае они учитывают только последний из этих символов.

Пример

format-number(123456789.0123,'0000,000,00') 
 '1,23,45,67,89'

Дробная часть числа, представленная нетерминалом

NFFraction
, начинается символом-разделителем целой и дробной части
NFFractionDelim
(по умолчанию "
.
"), продолжается последовательностью символов обязательных позиций цифр
NFReqDigit
и заканчивается последовательностью символов необязательных позиций
NFOptDigit
:

[NF 6] NFFraction ::= NFFractionDelim NFReqDigit* NFOptDigit*

Примеры

format-number(1234.567,'#.00') 
 '1234.57'

format-number(1234.567,'#.00#') 
 '1234.567'

format-number(1234.567,'#.0000') 
 '1234.5670'

Продукция

NFChar
, использующаяся при определении префикса (
NFPrefix
) и суффикса (
NFSuffix
), может содержать любые неформатирующие символы:

[NF 7] NFChar ::= (Char - NFSymbol)

К специальным форматирующим символам относятся следующие:

□ символ обязательной позиции цифры (по умолчанию "

0
");

□ символ необязательной позиции цифры (по умолчанию "

#
");

□ символ-разделитель образцов форматирования для положительного и отрицательного числа (по умолчанию "

;
");

□ символ-разделитель целой и дробной части (по умолчанию "

.
");

□ символ процента (по умолчанию "

%
").

Перечислим их продукции:

[NF 8] NFSymbol           ::= NFReqDigit

                              | NFOptDigit

                              | NFSubpatternDelim

                              | NFFractionDelim

                              | NFGroupDelim

                              | NFPercent

[NF 9] NFReqDigit         ::= '0'

[NF 10] NFOptDigit        ::= '#'

[NF 11] NFSubpatternDelim ::= ';'

[NF 12] NFFractionDelim   ::= '.'

[NF 13] NFGroupDelim      ::= ','

[NF 14] NFPercent         ::= '%'

Синтаксические правила, которые мы привели выше, пока не являются стандартными. Они корректно передают синтаксис образца форматирования, но являются более строгими, чем определения в документации языка Java.

Элемент xsl:decimal-format

Синтаксис элемента задан конструкцией вида:

 name="имя"

 decimal-separator="символ"

 grouping-separator="символ"

 infinity="строка"

 minus-sign="символ"

 NaN="строка"

 percent="символ"

 per-mille="символ"

 zero-digit="символ"

 digit="символ"

 pattern-sераrator="символ"/>

XSLT позволяет изменять специальные символы, влияющие на форматирование строки. Именованный набор таких символов и некоторых других указаний называется десятичным форматом и определяется элементом

xsl:decimal-format
. От атрибутов этого элемента зависит, как будут обрабатываться символы образца форматирования и как число будет отображаться на выходе:

Атрибут

name
элемента
xsl:decimal-format
задает расширенное имя десятичного формата. Если имя не указано, это означает, что элемент
xsl:decimal-format
определяет десятичный формат по умолчанию.

Остальные атрибуты контролируют интерпретацию форматирующего образца и вывод строкового представления числа следующим образом:

decimal-separator
— задает символ, разделяющий целую и дробную части числа. Значением этого атрибута по умолчанию является символ "
.
", с Unicode-кодом
#x2e
. Атрибут
decimal-separator
рассматривается как специальный символ образца форматирования. Кроме того, он будет использован как разделяющий символ при выводе;

grouping-separator
— задает символ, группирующий цифры в целой части записи числа. Такие символы используются, например, для группировки тысяч ("
1,234,567.89
"). Значением по умолчанию является символ "
,
", код
#x2c
.
grouping-separator
рассматривается как специальный символ образца форматирования. Помимо этого, он будет использован как разделяющий символ групп цифр при выводе числа;

percent
— задает символ процента. Значением по умолчанию является символ "
%
", код
#x25
. Этот символ будет распознаваться в образце форматирования и использоваться при выводе;

per-mille
— задает символ промилле. Значением по умолчанию является символ "
", код
#х2030
. Символ промилле распознается в образце форматирования и используется в строковом представлении числа;

zero-digit
— задает символ нуля. Значением по умолчанию является символ "
0
", код
#x30;
. В качестве цифр при отображении числа будут использоваться символ нуля и 9 символов, следующих за ним. Символ нуля распознается в образце форматирования и используется при выводе строкового представления числа;

digit
— определяет символ, который используется в образце форматирования для определения позиции необязательного символа. Значением по умолчанию является символ "
#
". Этот символ распознается как форматирующий символ необязательной цифры. Он не включается в строковое представление числа;

pattern-separator
— определяет символ, который используется в образце форматирования для разделения положительного и отрицательного форматов числа. Он не включается в строковое представление числа. Значением этого атрибута по умолчанию является символ "
;
";

infinity
— задает строку, которая будет представлять бесконечность. Значением по умолчанию является строка "
Infinity
";

NaN
— задает строку, которая будет представлять не-числа. Значением по умолчанию является строка "
NaN
";

minus-sign
— задает символ, который будет использоваться для обозначения отрицательных чисел. Значением по умолчанию является символ "
-
", код
#x2D
.

Элемент

xsl:decimal-format
не имеет смысла без функции
format-number
. Все, на что влияют его атрибуты — это формат, который будет использоваться при преобразовании чисел в строку функцией
format-number
.

Примеры

Определение десятичного формата:

 name="format1"

 decimal-separator=","

 minus-sign="N"

 grouping-separator=":"

 infinity="∞"

 NaN="not-a-number"

 percent="%"

 digit="$"

 pattern-separator="|"/>

Примеры функций

format-number
:

format-number(123456.78, '$,0000', 'format1) 
 '123456,7800'

format-number(-123456.78, '$,00$$', 'format1') 
 'N123456,78'

format-number(123456.78, '$,0000|$,0000-', 'format1') 
 '123456,7800'

format-number(-123456.78, '$,00001$,0000-', 'format1') 
 '123456,7800-'

format-number(-123456.78, '000:000:000,00$$', 'format1') 
 'N000:123:456,78'

format-number('zero', '000:000:000,00$$', 'format1') -> 'not-a-number'

format-number(1 div 0, '$,$', 'format1') 
 '∞'

format-number(-1 div 0, '$,$', 'format1') 
 'N∞'

Определение десятичного формата:

Примеры функций

format-number
:

format-number(123456789, '#', 'format2') 
 '012345678'

format-number(123456789, '#') 
 '123456780'

Определение десятичного формата:

Примеры функций

format-number
:

format-number(123456789, '#', 'format3') 
 '23456789:'

format-number(12345.06789, '#.#####', 'format3') 
 '23456.1789:'

Десятичный формат, определяемый элементом

xsl:decimal-format
, в отличие от многих других элементов не может переопределяться в преобразованиях со старшим порядком импорта. Элементы
xsl:decimal-format
должны определять десятичные форматы с различными именами (за исключением тех случаев, когда значения их атрибутов полностью совпадают).

Контроль вывода документа