С помощью инструкций xsl можно в конечном дереве производить нумерацию. Для этой цели используется инструкция xsl:number
. Она позволяет поместить в конечное дерево форматированное число.
Синтаксис:
1 2 3 4 5 6 7 8 9 10 | <xsl:number value = "XPath" level = "single|multiple|any" count = "XPath" from = "XPath" format = "строка" lang = "строка" letter-value = "alphabetic|traditional" grouping-separator = "символ" grouping-size = "число" /> |
Атрибуты:
value
— необязательный атрибут, задает само число. Его значением является выражение XPath. Это выражение обрабатывается, а полученный объект преобразуется в число (с плавающей точкой) по следующим правилам:Затем это число округляется до целого и преобразуется в строку с помощью атрибутов форматирования, описанных ниже. После преобразования полученная строка подставляется в конечное дерево. Если атрибутvalue
не указан, инструкцияxsl:number
вставляет число, основанное на позиции текущего узла в исходном дереве. При этом учитывается значение атрибутовlevel
,count
,from
. Именно эти атрибуты в данном случае будут определять, как пронумеровать текущий узел. Если все эти атрибуты (или какой-то один из них) отсутствуют, то берется их значение по умолчанию и инструкцияxsl:number
просто вставит число равное позиции текущего узла среди узлов того же уровня (т.е. среди его братьев — siblings).- строка, начинающаяся с числа, после которого идет пробельный символ, преобразовывается в это число. Все остальное содержимое этой строки не учитывается. Перед числом также может стоять пробельный символ и знак минус. Все остальные строки преобразуются в
NaN
(не число); - булево значение
true
преобразуется в 1, булево значениеfalse
преобразуется в 0; - набор узлов сперва преобразуется в строку, которая затем преобразуется в число по описанному выше алгоритму.
- строка, начинающаяся с числа, после которого идет пробельный символ, преобразовывается в это число. Все остальное содержимое этой строки не учитывается. Перед числом также может стоять пробельный символ и знак минус. Все остальные строки преобразуются в
level
– определяет, какие уровни (или точнее, узлы на каких уровнях) исходного дерева следует учитывать при нумерации. Под уровнем здесь понимаются узлы одного поколения, т.е. siblings (братья). Атрибут может принимать значенияsingle
, multiple илиany
. По умолчанию используетсяsingle
. При вариантеsingle
считаются элементы на одном уровне,multiple
– на нескольких,any
– на всех.count
– задает шаблон (XPath) определяющий, какие узлы следует считать на уровнях выбранных предыдущим атрибутом. Узлы, не соответствующие шаблону, в расчет не принимаются. Если атрибутcount
не указан, то по умолчанию он содержит шаблон, соответствующий любому узлу того же типа, что и текущий узел, а если у текущего узла есть имя, то с таким же именем.from
– задает область счета, точнее верхний ее предел. Его значением является шаблон (XPath), указывающий, откуда начинать отсчет (с какого узла). Нижним пределом области счета всегда будет текущий узел. Если атрибутfrom
не указан, то по умолчанию он содержит шаблон, соответствующий корневому элементу.format
– его значение является строкой и представляет собой что-то вроде маски форматирования. Она состоит из так называемых лексем – максимальных последовательностей буквенно-цифровых символов (т.е. букв и цифр) и максимальных последовательностей не буквенно-цифровых символов (т.е. не букв или цифр). Иными словами, различаются два вида лексем: буквенно-цифровые и не буквенно-цифровые. Буквенно-цифровые лексемы интерпретируются как образцы для форматирования чисел, а не буквенно-цифровые лексемы как так называемые разделяющие последовательности, т.е. символы, разделяющие числа между собой. Особо нужно отметить, что лексемой являются не отдельные символы, а именно максимальные последовательности символов одного вид (буквенно-цифровых или не буквенно-цифровых). Проще говоря, все буквенно-цифровые символы, идущие друг за другом, до первого не буквенно-цифрового символа, образуют одну буквенно-цифровую лексему, служащую образцом для форматирования одного числа, а все не буквенно-цифровые символы, идущие друг за другом, до первого буквенно-цифрового символа, образуют одну не буквенно-цифровую лексему, интерпретируемую как одна разделяющая последовательность. Разделяющие последовательности вставляются в отформатированное число так, как они есть (т.е. без каких-либо преобразований) и в том самом месте, в котором они стоят в маске. Они могут состоять из одного символа или нескольких. Разделяющие последовательности могут предшествовать числу, стоять после числа или разделять числа между собой. Буквенно-цифровые символы интерпретируются как образцы для форматирования чисел. Они не вставляются в форматированное число как есть (поэтому не могут быть разделителями), а указывают процессору как следует отформатировать число. При этом во внимание принимаются следующие правила:- символ 1 форматирует число арабскими цифрами: 1, 2, … , 10, 11, …
- последовательность символов 01, 001, … также форматирует число арабским цифрами, но при этом дополняет его предшествующими нулями, если оно короче данного последовательности
- символ А форматирует число заглавными буквами латинского алфавита
- символ а форматирует число строчными буквами латинского алфавита
- символ I форматирует число заглавными римскими цифрами
- символ i форматирует число строчными римскими цифрами
- любой другой буквенно-цифровой символ отформатирует число в соответствии с вышеперечисленными правилами, но за начало отсчет будет взят именно этот символ. Например, символ 2 преобразует число 5 в 6, символ С в G и так далее.
Если атрибут
format
не указан, то по умолчанию он имеет значение «1». Разделителем же по умолчанию будет точка.lang
– позволяет указать, алфавит какого языка следует использовать при буквенной нумерации. Однако на практике XSLT-процессоры редко поддерживают возможность буквенной нумерации на каких-либо языках кроме латиницы. Поэтому лучше использовать другой метод.letter-value
– устраняет неясности в буквенных нумерациях. Во многих языках обычно используются две основные буквенные нумерации: в одной нумерация производится буквами в алфавитном порядке, в другой так же буквами, но несколько в другом, не алфавитном порядке. Самый распространенный пример – нумерация римскими цифрами, которые, по сути, являются латинскими буквами. Проблема может возникнуть, если понадобиться нумерация латинскими буквами в алфавитном порядке начиная с буквы i. Если в этом случае в атрибутеformat
поставить лексему i, то получится нумерация римскими цифрами. В некоторых же языках первый элемент и алфавитной, и традиционной нумерации одинаков, и потому одной лексемы форматирования будет явно недостаточно. Решить эту проблему помогает атрибутletter-value
. Если он имеет значениеalphabetic
, это указывает на алфавитную последовательность, значениеtraditional
– на альтернативную (например, римскими цифрами).grouping-separator
иgrouping-size
– позволяют разделять одно длинное число на группы (например, группировать десятичные разряды). Атрибутgrouping-separator
указывает знак, который будет использоваться в виде разделителя групп, а атрибутgrouping-size
задает размер группы (длину в символах). Например, чтобы число 1000000 представить в виде 1,000,000 необходимо атрибутуgrouping-separator
присвоить значение «,
«, а атрибутуgrouping-size
значение «3». Эти атрибуты используются в паре. Если один из них отсутствует, второй будет проигнорирован.
При использовании атрибутов level
, count
, from
возможны три варианта определения подставляемого числа. Зависят они от значения атрибута level
.
level = "single"
Данный вариант позволяет вычислить номер узла исходя из его позиции среди узлов того же уровня (т.е. среди его братьев — siblings). Нумерация в этом случае будет одноуровневая. Номер вычисляется по следующему алгоритму:- Сначала определяется область нумерации. Она находится на оси
ancestor-or-self
относительно текущего узла (т.е. на оси включающей его самого и его предков). Нижней границей области нумерации будет сам текущий узел. Верхняя граница зависит от значения атрибутаfrom
. Определяется она так: на той же осиancestor-or-self
находится ближайший предок текущего узла, соответствующий шаблону, заданному атрибутомfrom
. Дети (непосредственные потомки) этого предка и будут верхней границей области нумерации. Если атрибутfrom
не задан, то верхней границей области нумерации будут дети (непосредственные потомки) корневого элемента. - Затем определяется нумеруемый узел: в границах области нумерации находится первый (т.е. ближайший к текущему узлу) узел, соответствующий шаблону, заданному атрибутом
count
. Поскольку поиск осуществляется на осиancestor-or-self
, то этим узлом может быть только предок текущего узла или сам текущий узел. - Далее определяется номер найденного на предыдущем этапе узла. Именно этот номер и будет в итоге вставлен инструкцией
xsl:number
в конечное дерево. Для простоты понимания можно сказать, что это будет порядковый номер найденного на втором этапе узла среди его братьев (siblings), соответствующих образцуcount
(т.е. в расчет берутся не все братья, а лишь одноименные/однотипные с найденным узлом). В более строгом определении этот номер равен: 1 плюс количество узлов, лежащих на осиpreceding-sibling
относительно узла найденного на втором этапе, и так же как этот узел, соответствующих образцуcount
. Или иными словами, 1 плюс количество предшествующих одноименных братьев узла, найденного на втором этапе.
- Сначала определяется область нумерации. Она находится на оси
level = "multiple"
Данный вариант похож на предыдущий, но несколько сложнее, поскольку позволяет считать узлы на нескольких уровнях исходного дерева. Соответственно нумерация в этом случае будет многоуровневая, т.е. вставляемое инструкцией число будет состоять из нескольких разделенных номеров узлов. А вычисляются эти номера следующим образом:- Сначала, как и в первом варианте, определяется область нумерации. Причем определяется она абсолютно так же как в первом варианте: находится она на оси
ancestor-or-self
относительно текущего узла, нижней границей является сам текущий узел, а верхняя зависит от значения атрибутаfrom
(дети ближайшего к текущему узлу предка, соответствующего шаблонуfrom
). - Далее, как и в первом варианте, определяются нумеруемые узлы. Отличие состоит в том, что в первом варианте был один нумеруемый узел, здесь же их будет несколько и на разных уровнях. Поэтому их нужно не только найти, но и расположить в правильном порядке. Происходит это следующим образом: сперва строится перечень всех узлов в границах области нумерации, т.е. на оси
ancestor-or-self
от верхней границы, определенной на предыдущем этапе, до текущего узла. Понятно, что в этот перечень могут войти только предки текущего узла и он сам. Причем располагаться узлы в этом перечне будут в том порядке, в котором они встречаются в исходном дереве, а завершит список сам текущий элемент. Затем из этого перечня удаляются все узлы, не соответствующие образцуcount
(т.е. остаются только те, которые ему соответствуют). - И, наконец, на третьем этапе определяется номер каждого из найденных узлов. Происходит это так же, как и в первом варианте, с той разницей, что номер определяется для каждого из найденных узлов. Т.е. для каждого найденного узла определяется порядковый номер (позиция) среди его братьев (siblings), соответствующих образцу
count
. Соответственно номер этот равен: 1 плюс количество узлов, лежащих на осиpreceding-sibling
относительно найденного узла, и так же как этот узел, соответствующих образцуcount
. Или иными словами, 1 плюс количество предшествующих одноименных братьев узла, найденного на втором этапе. Эти номер, в порядке определенном на втором этапе, через разделительный знак (разделительный знак определяется атрибутами форматирования) вставляются в конечное дерево.
- Сначала, как и в первом варианте, определяется область нумерации. Причем определяется она абсолютно так же как в первом варианте: находится она на оси
level = "any"
Данный вариант позволяет вычислить номер узла исходя из его позиции среди узлов всех учитываемых уровней. Иными словами ведется сплошная нумерация, уровни (или точнее, нахождение нумеруемых узлов на разных уровнях) в расчет не принимаются. Узлы нумеруются так, как будто они находятся на одном уровне. Алгоритм следующий:- Сначала как обычно определяется область нумерации. В отличие от первых двух вариантов она включает в себя узлы на осях
preceding
иancestor
. Нижней ее границей будет узел, идущей непосредственно перед текущим узлом, а верхняя определяется атрибутомfrom
: на осяхpreceding
иancestor
находится ближайший к текущему узлу узел, соответствующий шаблону, заданному атрибутомfrom
. Дети (непосредственные потомки) этого узла и будут верхней границей области поиска. Если атрибутfrom
не задан, то верхней границей области поиска будут дети (непосредственные потомки) корневого элемента. Для простоты понимания можно сказать, что областью поиска в данном случае будут все узлы, предшествующие в исходном документе текущему узлу (т.е. расположенные выше него, как братья, так и предки), но расположенные после узла, соответствующего атрибутуfrom
. - Далее определяется, какие узлы следует нумеровать, а какие исключить из нумерации. Нумеруются узлы, лежащие в пределах области поиска и соответствующие атрибуту
count
. Все остальные узлы из нумерации исключаются. - И, наконец, определяется номер, который будет вставлен инструкцией
xsl:number
в конечное дерево. Он равен 1 плюс количество узлов, лежащих в области поиска и соответствующие атрибутуcount
. Текущий узел не считается, поскольку в данном случае он не входит в область поиска.
- Сначала как обычно определяется область нумерации. В отличие от первых двух вариантов она включает в себя узлы на осях
После того как конкретное число получено оно преобразуется в строку и вставляется в конечное дерево. При этом инструкция xsl:number
позволяет форматировать это число, с помощью атрибутов форматирования.