Speak.Me Учить иностранные слова

XSL: числа и нумерация, инструкция xsl:number

С помощью инструкций xsl можно в конечном дереве производить нумерацию. Для этой цели используется инструкция xsl:number. Она позволяет поместить в конечное дерево форматированное число.

Синтаксис:

Атрибуты:

  • 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). Нумерация в этом случае будет одноуровневая. Номер вычисляется по следующему алгоритму:

    1. Сначала определяется область нумерации. Она находится на оси ancestor-or-self относительно текущего узла (т.е. на оси включающей его самого и его предков). Нижней границей области нумерации будет сам текущий узел. Верхняя граница зависит от значения атрибута from. Определяется она так: на той же оси ancestor-or-self находится ближайший предок текущего узла, соответствующий шаблону, заданному атрибутом from. Дети (непосредственные потомки) этого предка и будут верхней границей области нумерации. Если атрибут from не задан, то верхней границей области нумерации будут дети (непосредственные потомки) корневого элемента.
    2. Затем определяется нумеруемый узел: в границах области нумерации находится первый (т.е. ближайший к текущему узлу) узел, соответствующий шаблону, заданному атрибутом count. Поскольку поиск осуществляется на оси ancestor-or-self, то этим узлом может быть только предок текущего узла или сам текущий узел.
    3. Далее определяется номер найденного на предыдущем этапе узла. Именно этот номер и будет в итоге вставлен инструкцией xsl:number в конечное дерево. Для простоты понимания можно сказать, что это будет порядковый номер найденного на втором этапе узла среди его братьев (siblings), соответствующих образцу count (т.е. в расчет берутся не все братья, а лишь одноименные/однотипные с найденным узлом). В более строгом определении этот номер равен: 1 плюс количество узлов, лежащих на оси preceding-sibling относительно узла найденного на втором этапе, и так же как этот узел, соответствующих образцу count. Или иными словами, 1 плюс количество предшествующих одноименных братьев узла, найденного на втором этапе.
  • level = "multiple"
    Данный вариант похож на предыдущий, но несколько сложнее, поскольку позволяет считать узлы на нескольких уровнях исходного дерева. Соответственно нумерация в этом случае будет многоуровневая, т.е. вставляемое инструкцией число будет состоять из нескольких разделенных номеров узлов. А вычисляются эти номера следующим образом:

    1. Сначала, как и в первом варианте, определяется область нумерации. Причем определяется она абсолютно так же как в первом варианте: находится она на оси ancestor-or-self относительно текущего узла, нижней границей является сам текущий узел, а верхняя зависит от значения атрибута from (дети ближайшего к текущему узлу предка, соответствующего шаблону from).
    2. Далее, как и в первом варианте, определяются нумеруемые узлы. Отличие состоит в том, что в первом варианте был один нумеруемый узел, здесь же их будет несколько и на разных уровнях. Поэтому их нужно не только найти, но и расположить в правильном порядке. Происходит это следующим образом: сперва строится перечень всех узлов в границах области нумерации, т.е. на оси ancestor-or-self от верхней границы, определенной на предыдущем этапе, до текущего узла. Понятно, что в этот перечень могут войти только предки текущего узла и он сам. Причем располагаться узлы в этом перечне будут в том порядке, в котором они встречаются в исходном дереве, а завершит список сам текущий элемент. Затем из этого перечня удаляются все узлы, не соответствующие образцу count (т.е. остаются только те, которые ему соответствуют).
    3. И, наконец, на третьем этапе определяется номер каждого из найденных узлов. Происходит это так же, как и в первом варианте, с той разницей, что номер определяется для каждого из найденных узлов. Т.е. для каждого найденного узла определяется порядковый номер (позиция) среди его братьев (siblings), соответствующих образцу count. Соответственно номер этот равен: 1 плюс количество узлов, лежащих на оси preceding-sibling относительно найденного узла, и так же как этот узел, соответствующих образцу count. Или иными словами, 1 плюс количество предшествующих одноименных братьев узла, найденного на втором этапе. Эти номер, в порядке определенном на втором этапе, через разделительный знак (разделительный знак определяется атрибутами форматирования) вставляются в конечное дерево.
  • level = "any"
    Данный вариант позволяет вычислить номер узла исходя из его позиции среди узлов всех учитываемых уровней. Иными словами ведется сплошная нумерация, уровни (или точнее, нахождение нумеруемых узлов на разных уровнях) в расчет не принимаются. Узлы нумеруются так, как будто они находятся на одном уровне. Алгоритм следующий:

    1. Сначала как обычно определяется область нумерации. В отличие от первых двух вариантов она включает в себя узлы на осях preceding и ancestor. Нижней ее границей будет узел, идущей непосредственно перед текущим узлом, а верхняя определяется атрибутом from: на осях preceding и ancestor находится ближайший к текущему узлу узел, соответствующий шаблону, заданному атрибутом from. Дети (непосредственные потомки) этого узла и будут верхней границей области поиска. Если атрибут from не задан, то верхней границей области поиска будут дети (непосредственные потомки) корневого элемента. Для простоты понимания можно сказать, что областью поиска в данном случае будут все узлы, предшествующие в исходном документе текущему узлу (т.е. расположенные выше него, как братья, так и предки), но расположенные после узла, соответствующего атрибуту from.
    2. Далее определяется, какие узлы следует нумеровать, а какие исключить из нумерации. Нумеруются узлы, лежащие в пределах области поиска и соответствующие атрибуту count. Все остальные узлы из нумерации исключаются.
    3. И, наконец, определяется номер, который будет вставлен инструкцией xsl:number в конечное дерево. Он равен 1 плюс количество узлов, лежащих в области поиска и соответствующие атрибуту count. Текущий узел не считается, поскольку в данном случае он не входит в область поиска.

После того как конкретное число получено оно преобразуется в строку и вставляется в конечное дерево. При этом инструкция xsl:number позволяет форматировать это число, с помощью атрибутов форматирования.