Перейти к содержанию

xsl:number

Элемент xsl:number вычисляет номер узла в соответствии с заданными критериями, форматирует его и затем вставляет в результирующее дерево в виде текстового узла.

Синтаксис

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<xsl:number
  level="single | multiple | any"
  count="паттерн"
  from="паттерн"
  value="выражение"
  format="строка"
  lang="токен"
  letter-value="alphabetic | traditional"
  grouping-separator="символ"
  grouping-size="число"
/>

Атрибуты:

level
необязательный атрибут, указывает, на каких уровнях дерева следует искать нумеруемые узлы.
count
необязательный атрибут, указывает, какие именно узлы следует считать при вычислении номера.
from
необязательный атрибут, указывает, в какой части документа будет производиться нумерация.
value
необязательный атрибут, задает выражения, которые следует использовать для вычисления значения номера.
format
необязательный атрибут, определяет, как номер будет форматироваться в строку.
lang
необязательный атрибут, задает языковой контекст нумерации.
letter-value
необязательный атрибут, определяет параметры буквенных методов нумерации.
grouping-separator
необязательный атрибут, задает символ, разделяющий группы цифр в номере.
grouping-size
необязательный атрибут, определяет количество цифр в одной группе.

Описание и примеры

Нумерация, несомненно, является одной из самых естественных проблем, решаемых при помощи XSLT. Задача нумерации состоит в том, чтобы, исходя из позиции обрабатываемого узла в дереве документа, вычислить по заданным критериям его порядковый номер. В качестве примера такого рода задачи можно привести вывод номеров частей, разделов и глав книги, указание номеров элементов списка или строк таблицы.

Для вычисления порядковых номеров узлов в дереве в XSLT существует несколько способов. В простых случаях для достижения цели бывает достаточно воспользоваться одним из следующих XPath-выражений.

  • Для того чтобы получить порядковый номер текущего узла в обрабатываемом множестве, можно использовать функцию position. Обратим внимание, что это будет позиция узла в обрабатываемом в данный момент множестве, а не в дереве исходящего документа.
  • Функция count(preceding-sibling::*)+1 возвращает порядковый номер текущего элемента среди других элементов его родителя, иначе говоря, среди его братьев. Путь выборки preceding-sibling::* выбирает множество братских элементов, предшествующих текущему узлу, а функция count вычисляет их количество. Таким образом, значение count(preceding-sibling::*)+1 будет равно 1 для первого элемента (поскольку ему другие элементы не предшествуют), 2 — для второго (ему предшествует один элемент) и так далее.
  • Для того чтобы учитывать при подсчете только определенные элементы, можно переписать предыдущее выражение в чуть более строгом виде. Например, выражение, считающее только элементы chapter, будет задаваться следующим образом: (preceding-sibling::chapter) +1.
  • Глубина текущего узла от корня дерева может быть вычислена выражением count(ancestor-or-self::node()). Это выражение будет возвращать 1 для корневого узла, 2 для элемента документа и так далее.

Вычислять выражения и выводить вычисленные значения в результирующее дерево следует, как и обычно — при помощи элемента xsl:value-of.

Пример 1

1
2
3
<xsl:value-of
  select="count(preceding-sibling::chapter)+1"
/>

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

Другим, несравненно более легким и удобным способом нумерации и индексирования узлов является использование элемента xsl:number.

Выполнение элемента xsl:number можно условно разделить на два этапа — вычисление номера и его строковое форматирование. На этапе вычисления активными являются атрибуты level, count, from и value. Форматирование производится с учетом значений атрибутов format, lang, letter-value, grouping-separator и grouping-size. Результатом первого этапа является список номеров, который форматируется в текстовый узел на втором этапе.

Вычисление номеров

Пожалуй, самым простым для понимания (но не самым простым в использовании) способом вычисления номера является использование XPath-выражений. Этот способ практически идентичен использованию xsl:value-of, как было показано выше. Единственным отличием xsl:number является то, что после вычисления номера он сначала форматируется, а потом уже вставляется в результирующее дерево в виде текстового узла.

Результатом первого этапа форматирования при определенном атрибуте value является список, состоящий из числа, полученного в результате вычисления выражения, указанного в значении этого атрибута.

Пример 2

В этом и нескольких следующих примерах мы будем вычислять номера в одном и том же документе, который представлен в листинге 8.31.

Листинг 8.31. Входящий документ для примеров преобразований с использованием xsl:number

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<doc>
  <chapter title="First chapter">
    <section title="First section">
      <para>paragraph 1</para>
      <para>paragraph 2</para>
      <para>paragraph 3</para>
    </section>
    <section title="Second section">
      <para>paragraph 4</para>
      <para>paragraph 5</para>
    </section>
  </chapter>
  <chapter title="Second chapter">
    <section title="Third section">
      <para>paragraph 6</para>
      <para>paragraph 7</para>
      <para>paragraph 8</para>
      <para>paragraph 9</para>
    </section>
    <section title="Forth section">
      <para>paragraph 10</para>
      <para>paragraph 11</para>
      <para>paragraph 12</para>
    </section>
    <section title="Fifth section">
      <para>paragraph 13</para>
      <para>paragraph 14</para>
      <para>paragraph 15</para>
      <para>paragraph 16</para>
    </section>
  </chapter>
  <chapter title="Third chapter">
    <section title="Sixth section">
      <para>paragraph 17</para>
      <para>paragraph 18</para>
    </section>
  </chapter>
</doc>

В качестве первого примера приведем два шаблона, обрабатывающих элементы chapter: один с использованием xsl:value-of, а второй с использованием xsl:number.

Листинг 8.32. Вариант нумерующего шаблона с использованием xsl:value-of

1
2
3
4
5
6
7
8
<xsl:template match="chapter">
  <xsl:value-of select="position()" />
  <xsl:text>.</xsl:text>
  <xsl:value-of select="@title" />
  <xsl:text>

  </xsl:text>
</xsl:template>

Листинг 8.33. Вариант нумерующего шаблона с использованием xsl:number

1
2
3
4
5
6
7
<xsl:template match="chapter">
  <xsl:number value="position()" format="1. " />
  <xsl:value-of select="@title" />
  <xsl:text>

  </xsl:text>
</xsl:template>

Результат обоих шаблонов имеет следующий вид:

1
2
3
1. First chapter
2. Second chapter
3. Third chapter

Использование xsl:number даже в этом простом случае сэкономило одну строчку в коде. Однако, если бы вместо нумерации арабскими цифрами (1, 2, 3 и т.д.) нужно было применить нумерацию римскими цифрами (I, II, III и т.д.), в преобразовании с xsl:number мы бы изменили всего один символ (вместо format="1. " указали бы format="I. "), в то время как в преобразовании с xsl:value-of пришлось бы писать сложную процедуру преобразования числа в римскую запись.

В том случае, если атрибут value опущен, номера элементов вычисляются исходя из значений атрибутов level, count и from.

Атрибут level имеет три варианта значений: single, multiple и any, значением по умолчанию является single. Процедура вычисления номеров существенным образом зависит от того, какой из этих вариантов используется — при методе single считаются элементы на одном уровне, при методе multiple — на нескольких уровнях и при методе any — на любых уровнях дерева. Алгоритм вычисления списка номеров в каждом из случаев не слишком сложен, но понять его только по формальному описанию довольно непросто. Поэтому каждый из методов будет дополнительно проиллюстрирован примерами вычисления.

Атрибут count содержит паттерн, которому должны удовлетворять нумеруемые узлы. Узлы, не соответствующие этому образцу, просто не будут приниматься в расчет. Значением этого атрибута по умолчанию является паттерн, выбирающий узлы с тем же типом и именем, что и у текущего узла (если, конечно, у него есть имя).

Атрибут from содержит паттерн, который определяет так называемую область нумерации, или область подсчета. При вычислении номера будут приниматься во внимание только те нумеруемые узлы, которые принадлежат этой области. По умолчанию областью подсчета является весь документ.

Метод single

Метод single используется для того, чтобы вычислить номер узла, основываясь на его позиции среди узлов того же уровня. Нумерацию, в которой используется метод single, также называют одноуровневой нумерацией.

Областью нумерации этого метода будет множество всех потомков ближайшего предка текущего узла, удовлетворяющего паттерну, указанному в атрибуте from.

Вычисление номера производится в два шага.

  • На первом шаге находится узел уровня дерева. Узлом уровня будет узел, удовлетворяющий следующим условиям:
  • он является первым (то есть ближайшим к текущему) узлом, принадлежащим оси ancestor-or-self текущего узла;
  • он удовлетворяет паттерну count;
  • он принадлежит области подсчета;
  • если такого узла нет, список номеров будет пустым.
  • На втором шаге вычисляется номер узла уровня. Этот номер будет равен 1 плюс количество узлов, принадлежащих оси навигации preceding-sibling и удовлетворяющих паттерну count.

Надо сказать, от атрибута from в методе single мало пользы. Единственный эффект, который можно от него получить, — это пустой список номеров в случае, если первый узел, принадлежащий оси ancestor-or-self и удовлетворяющий паттерну count, не будет иметь предка, соответствующего паттерну атрибута from.

Пример 3

Разберем функционирование одноуровневой нумерации в следующем шаблоне:

1
2
3
4
5
6
7
8
<xsl:template match="para">
  <xsl:number format="     1." count="section" />
  <xsl:number format="1." count="para" />
  <xsl:value-of select="." />
  <xsl:text>

  </xsl:text>
</xsl:template>

Мы продемонстрируем вычисление номера одного из элементов para на схематическом изображении дерева обрабатываемого документа (рис. 8.1). Узел обрабатываемого элемента мы выделим полужирной линией, узел элемента doc пометим буквой d, узлы элементов chapter — буквой c, элементов section и para — буквами s и p соответственно.

Рис. 8.1. Дерево обрабатываемого документа

В качестве первого примера приведем вычисление номера элементом

1
<xsl:number format="     1." count="section" />

На первом шаге нам нужно найти узел уровня дерева. Этим узлом будет первый элемент section, являющийся предком текущего узла. На рис. 8.2 он обведен пунктиром.

Рис. 8.2. Первый шаг вычисления номера

Номер этого элемента будет равен 1 плюс количество предшествующих ему братских элементов section. Это множество выделено пунктиром на рис. 8.3.

Рис. 8.3. Второй шаг вычисления номера

Выделенное множество содержит два узла. Таким образом, искомый номер будет равен 3.

Проведем такой же разбор для определения

1
<xsl:number format="1." count="para" />

В этом случае паттерну, указанному в элементе count удовлетворяет сам текущий узел, значит, он и будет являться узлом уровня, как это показано на рис. 8.4.

Рис. 8.4. Первый шаг вычисления номера

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

Рис. 8.5. Второй шаг вычисления номера

Выделенное множество содержит всего один узел, значит, искомый номер будет равен 2.

Таким образом, результатом обработки выделенного элемента para будет следующая строка:

1
    3.2.paragraph 14

Метод multiple

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

Область нумерации метода multiple определяется так же, как и в случае с методом single: учитываются только потомки ближайшего предка текущего узла, удовлетворяющего паттерну, указанному в атрибуте from.

Вычисление списка номеров узлов выполняется в два этапа:

  • На первом этапе выбирается множество нумеруемых узлов, удовлетворяющее следующим условиям:
  • его узлы принадлежат оси навигации ancestor-or-self текущего узла;
  • его узлы соответствуют паттерну count;
  • его узлы принадлежат области подсчета.
  • На втором этапе для каждого узла нумеруемого множества вычисляется позиция среди собратьев. Позиция нумеруемого узла будет равна 1 плюс количество узлов, принадлежащих его оси навигации preceding-sibling и соответствующих паттерну count.

Пример 4

Для демонстрации вычисления номеров на нескольких уровнях дерева документа проследим за выполнением инструкции

1
2
3
4
5
6
<xsl:number
  format="     1.1."
  level="multiple"
  count="doc|chapter|para"
  from="doc"
/>

при обработке того же элемента para.

Прежде всего, надо определить область подсчета. Значением атрибута from является паттерн doc, значит, подсчет будет вестись среди всех потомков ближайшего к текущему элементу para предка, который является элементом doc. Это множество выделено на рис. 8.6 штрих-пунктирной линией.

Рис. 8.6. Определение области подсчета

Следующим шагом выберем узлы, принадлежащие оси навигации ancestor-or-self текущего узла para и удовлетворяющие паттерну doc|chapter|para. Это множество будет включать сам текущий элемент, а также его предки chapter и doc. На рис. 8.7 они обведены пунктиром.

Рис. 8.7. Первый шаг вычисления номера

Следующим шагом оставим только те из выбранных узлов, которые входят в область подсчета. Эти узлы обведены на рис. 8.8 пунктиром.

Рис. 8.8. Второй шаг вычисления номера

Мы получили множество узлов, состоящее всего из двух элементов — chapter и para вследствие того, что элемент doc был исключен как не входящий в область подсчета. Выделим множества пересчитываемых узлов, предшествующих нумеруемым элементам (рис. 8.9).

Рис. 8.9. Третий шаг вычисления номера

В этом примере элемент chapter, так же как и элемент para, будет иметь номер 2. Соответственно, результатом выполнения инструкции xsl:number в этом случае будет строка

1
2.2.paragraph 14

Метод any

Метод any используется для того, чтобы вычислить номер узла, основываясь на его позиции среди всех учитываемых узлов элемента.

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

Номер вычисляется как 1 плюс количество узлов области подсчета, удовлетворяющих паттерну count и предшествующих в порядке просмотра документа текущему узлу.

Пример 5

В качестве примера применения метода any вычислим порядковый номер элемента para среди всех элементов документа, начиная со второй главы. Инструкцию такого рода мы запишем в виде

1
2
3
4
5
6
<xsl:number
  format="     1."
  level="any"
  count="*"
  from="chapter[2]"
/>

При ее выполнении мы сначала определим область, в которой будут подсчитываться узлы (обведены штрих-пунктирной линией на рис. 8.10).

Рис. 8.10. Определение области подсчета узлов

Следующим шагом выделим подмножество области подсчета, предшествующее в порядке просмотра текущему узлу para (рис. 8.11).

Рис. 8.11. Первый шаг вычисления номера

Выделенное множество содержит 11 узлов, значит, искомый номер будет равен 12.

Перед тем, как перейти к рассмотрению способов форматирования номеров, приведем итоговый пример (листинг 8.34), в котором в шаблонах будут использоваться все три метода нумерации.

Листинг 8.34. Шаблон, использующий разные методы нумерации

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<xsl:stylesheet
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
  <xsl:template match="doc">
    <xsl:text>Resulting document</xsl:text>
    <xsl:text>==================</xsl:text>
    <xsl:apply-templates select="chapter" />
  </xsl:template>
  <xsl:template match="chapter">
    <xsl:number format="1. " />
    <xsl:value-of select="@title" />
    <xsl:text>

    </xsl:text>
    <xsl:apply-templates select="section" />
  </xsl:template>
  <xsl:template match="section">
    <xsl:number
      format="   1.1 "
      level="multiple"
      count="chapter|section"
    />
    <xsl:value-of select="@title" />
    <xsl:text>

    </xsl:text>
    <xsl:apply-templates select="para" />
  </xsl:template>
  <xsl:template match="para">
    <xsl:number
      format="     a) "
      level="any"
      count="para"
    />
    <xsl:value-of select="." />
    <xsl:text>

    </xsl:text>
  </xsl:template>
</xsl:stylesheet>

Опишем словесно нумерацию, которая будет применяться в этом преобразовании.

  • Элементы chapter будут нумероваться в соответствии со своей позицией среди других элементов chapter того же уровня.
  • Элементы section будут нумероваться при помощи многоуровневой нумерации — номер будет состоять из номера элемента chapter и номера самого элемента section.
  • Элементы para будут нумероваться исходя из своей позиции среди всех остальных элементов para вне зависимости от того, на каких уровнях в документе они находятся.

Результатом применения этого преобразования к документу, приведенному в листинге 8.31, будет следующий текст.

Листинг 8.35. Выходящий документ

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Resulting document
==================
1. First chapter
    1.1 First section
        a) paragraph 1
        b) paragraph 2
        c) paragraph 3
    1.2. Second section
        d) paragraph 4
        e) paragraph 5
2. Second chapter
    2.1 Third section
        f) paragraph 6
        g) paragraph 7
        h) paragraph 8
        i) paragraph 9
    2.2 Forth section
        j) paragraph 10
        k) paragraph 11
        l) paragraph 12
    2.3 Fifth section
        m) paragraph 13
        n) paragraph 14
        o) paragraph 15
        p) paragraph 16
3. Third chapter
    3.1 Sixth section
        q) paragraph 17
        r) paragraph 18

Форматирование номеров

Возвращаясь немного назад, напомним, что результатом первого этапа выполнения xsl:number является список номеров, который может быть пустым или содержать одно или несколько чисел. Несложно увидеть, что количество номеров в этом списке будет зависеть от следующих условий.

  • Список номеров будет пустым, если в области нумерации не оказалось нумеруемых узлов.
  • Список номеров будет состоять не более чем из одного числа при использовании методов single и any.
  • Список номеров будет состоять из нуля или более чисел (по одному на каждый уровень нумерации) при использовании метода multiple.

На этапе форматирования список номеров преобразуется в строку и вставляется результирующее дерево в виде текстового узла.

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

Форматирование списка номеров производится в соответствии со значениями атрибутов format, lang, letter-value, grouping-separator и grouping-size, назначение и использование которых мы и будем разбирать в этом разделе.

Основным атрибутом форматирования является атрибут format, который содержит последовательность форматирующих токенов. Каждый форматирующий токен состоит из букв и цифр; он определяет процедуру форматирования для каждого числа из списка форматируемых номеров. В значении атрибута format форматирующие токены отделяются друг от друга сочетаниями символов, которые не являются буквами и цифрами. Такие сочетания называются разделяющими последовательностями. При форматировании они остаются в строковом выражении номера без изменений.

Пример 6

В примере к методу multiple мы использовали следующий элемент xsl:number:

1
2
3
4
5
6
<xsl:number
  format="     1.1."
  level="multiple"
  count="doc|chapter|para"
  from="doc"
/>

Разберем строение атрибута format этого элемента (на рис. 8.12 пробелы обозначены символами "_"):

Рис. 8.12. Строение атрибута format элемента xsl:number

Список номеров в том примере состоял из номера элемента chapter (числа 2) и номера элемента para (тоже 2). Номер, генерируемый элементом xsl:number, будет состоять из:

  • разделяющей последовательности "_____", которая будет скопирована, как есть;
  • числа 2, которое получается в результате форматирования номера 2 форматирующим токеном "1";
  • разделяющего символа ".";
  • числа 2, которое получается в результате форматирования номера 2 вторым форматирующим токеном "1";
  • разделяющего символа ".".

Объединив все эти части, мы получим отформатированный номер "_____2.2".

Несложно заметить, что главную роль при преобразовании списка номеров в их строковое представление играют форматирующие токены. Каждый такой токен преобразовывает соответствующий ему номер в строку. В табл. 8.3 мы приведем описания этих преобразований.

Таблица 8.3. Форматирующие токены

ТокенОписаниеПримеры
ТокенПреобразование
1Форматирует номер в виде строкового представления десятичного числа11 ? '1'
12 ? '2'
110 ? '10'
1999 ? '999'
11000 ? '1000'
0...01Форматирует номер в виде строкового представления десятичного числа; если получившая строка короче токена, она дополняется предшествующими нулями00011 ? '0001'
0012 ? '002'
00110 ? '010'
01999 ? '999'
000011000 ? '01000'
AФорматирует номер в виде последовательности заглавных букв латинского алфавитаA1 ? 'A'
A2 ? 'B'
A10 ? 'J'
A27 ? 'AA'
A999 ? 'ALK'
A1000 ? 'ALL'
aФорматирует номер в виде последовательности строчных букв латинского алфавитаa1 ? 'a'
a2 ? 'b'
a10 ? 'j'
a27 ? 'aa'
a999 ? 'alk'
a1000 ? 'all'
IФорматирует номер заглавными римскими цифрамиI1 ? 'I'
I2 ? 'II'
I10 ? 'X'
I27 ? 'XXVII'
I999 ? 'IM'
I1000 ? 'M'
iФорматирует номер строчными римскими цифрамиi1 ? 'i'
i2 ? 'ii'
i10 ? 'x'
i27 ? 'xxvii'
i999 ? 'im'
i1000 ? 'm'
ДругойФорматирует номер k как k-й член последовательности, начинающейся этим токеном. Если нумерация таким токеном не поддерживается, вместо него используется токен 1.Не поддерживающийся токен1 ? '1'
b10 ? 'k'
Б2 ? 'В'
Б27 ? 'Ы'
?999 ? '???'
?1000 ? '???'

При использовании алфавитной нумерации процессор может учитывать значение атрибута lang элемента xsl:number для того, чтобы использовать буквы алфавита соответствующего языка. Однако на практике возможность эта поддерживается очень слабо: большинство процессоров поддерживают алфавитную нумерацию только с использованием латиницы. Поэтому для того, чтобы использовать при алфавитной нумерации кириллицу, вместо атрибута lang следует использовать форматирующие токены "А" (русская заглавная буква "А") и "а" (русская строчная буква "а").

Пример 7

Для форматирования номеров в последовательности 1.1.а, 1.1.б, 1.1.в, …, 1.2.а и так далее можно использовать объявление вида:

1
2
3
4
5
6
<xsl:number
  format="1.&#х430;"
  level="multiple"
  count="chapter|section"
  from="doc"
/>

Представим теперь себе следующую ситуацию: нам нужно начать нумерацию с латинской буквы i для того, чтобы получить последовательность номеров вида i, j, k, l, m и так далее. Первое, что приходит в голову — это запись вида

1
<xsl:number format="i" ... />

Однако вместо требуемой последовательности мы получим последовательность строчных римских цифр: i, ii, iii и так далее. Иными словами, некоторые форматирующие токены определяют нумерующую последовательность двусмысленно: одним вариантом является алфавитная последовательность, начинающаяся этим токеном, другим — некая традиционная для данного языка (например, последовательность римских цифр для английского). Для того чтобы различать эти последовательности в двусмысленных ситуациях, в xsl:number существует атрибут letter-value. Если его значением является "alphabetic", нумерующая последовательность является алфавитной, значение "traditional" указывает на то, что следует использовать традиционный для данного языка способ. Если атрибут letter-value опущен, процессор может сам выбирать между алфавитным и традиционным способами нумерации.

При использовании цифровых форматов нумерации (иными словами, токенов вида 1, 01, 001 и так далее) цифры в номере можно разделить на группы, получив, например, такие номера как "2.00.00" из 20000 или "0-0-0-2" из 2. Для этой цели в xsl:number используется пара атрибутов grouping-separator и grouping-size.

Атрибут grouping-separator задает символ, который следует использовать для разбивки номера на группы цифр, в то время как grouping-size указывает размер группы. Эти атрибуты всегда должны быть вместе — если хотя бы один из них опущен, второй просто игнорируется.

Пример 8

Элемент xsl:number вида

1
2
3
4
5
<xsl:number
  format="[00000001]"
  grouping-separator="."
  grouping-size="2"
/>

будет генерировать номера в следующей последовательности:

1
2
3
4
5
1 ? '[00.00.00.01]'
2 ? '[00.00.00.02]'
...
999 ? '[00.00.09.99]'
1000 ? '[00.00.10.00]'

Пожалуй, следует упомянуть, что в значениях атрибутов format, lang, letter-value, grouping-size и grouping-separator могут быть указаны шаблоны значений, иными словами могут использоваться выражения в фигурных скобках. Это может быть полезно, например, для того, чтобы сгенерировать форматирующие токены во время выполнения преобразования.

Пример 9

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

1
2
3
4
5
6
7
8
<xsl:template match="section">
  <xsl:number
    format="{../@format}-1 "
    level="multiple"
    count="chapter|section"
  />
  <xsl:value-of select="@title" />
</xsl:template>

При обработке входящего документа

1
2
3
4
5
6
7
<doc>
  <chapter format="I" title="First Chapter">
    <section title="First Section" />
    <section title="Second Section" />
    <section title="Third Section" />
  </chapter>
</doc>

нумерация секций будет выглядеть как

1
2
3
I-1 First Section
I-2 Second Section
I-3 Third Section

Если же атрибут format элемента chapter будет иметь значение 1, секции будут пронумерованы в виде

1
2
3
1-1 First Section
1-2 Second Section
1-3 Third Section

Пример для XSLT 2.0

Для полноценной демонстрации применения xsl:number потребуется документ XML c достаточно большим количеством элементов для нумерации. Мы используем следующий документ:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
<?xml version="1.0" ?>
<!-- items-to-number.xml -->
<book>
  <chapter>
    <title>Alfa Romeo</title>
    <sect1>
      <title>Bentley</title>
    </sect1>
    <sect1>
      <title>Chevrolet</title>
      <sect2>
        <title>Dodge</title>
        <sect3>
          <title>Eagle</title>
        </sect3>
      </sect2>
    </sect1>
  </chapter>
  <chapter>
    <title>Ford</title>
    <sect1>
      <title>GMC</title>
      <sect2>
        <title>Honda</title>
        <sect3>
          <title>Isuzu</title>
        </sect3>
        <sect3>
          <title>Javelin</title>
        </sect3>
        <sect3>
          <title>K-Car</title>
        </sect3>
        <sect3>
          <title>Lincoln</title>
        </sect3>
      </sect2>
      <sect2>
        <title>Mercedes</title>
      </sect2>
      <sect2>
        <title>Nash</title>
        <sect3>
          <title>Opel</title>
        </sect3>
        <sect3>
          <title>Pontiac</title>
        </sect3>
      </sect2>
      <sect2>
        <title>Quantum</title>
        <sect3>
          <title>Rambler</title>
        </sect3>
        <sect3>
          <title>Studebaker</title>
        </sect3>
      </sect2>
    </sect1>
    <sect1>
      <title>Toyota</title>
    </sect1>
  </chapter>
</book>

Для сокращения объема выходных данных мы будем подсчитывать только элементы sect2. Начнем с использования атрибута ordinal:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?xml version="1.0" ?>
<!-- number8.xsl -->
<xsl:stylesheet
  version="2.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
  <xsl:output method="text" />
  <xsl:template match="book">
    <xsl:for-each select=".//sect2">
      <xsl:number
        level="any"
        count="chapter|sect1|sect2|sect3"
        format="Ww - "
        ordinal="yes"
      />
      <xsl:value-of select="title" />
      <xsl:text>

      </xsl:text>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

Словарная нумерация выглядит так:

1
2
3
4
5
Fourth - Dodge
Eighth - Honda
Thirteenth - Mercedes
Fourteenth - Nash
Seventeenth - Quantum

Теперь мы воспользуемся комбинацией format и lang:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?xml version="1.0" ?>
<!-- number9.xsl -->
<xsl:stylesheet
  version="2.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
  <xsl:output method="text" />
  <xsl:template match="book">
    <xsl:for-each select=".//sect2">
      <xsl:number
        level="any"
        count="chapter|sect1|sect2|sect3"
        format="w - "
        lang="de"
      />
      <xsl:value-of select="title" />
      <xsl:text>

      </xsl:text>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

При обработке этой таблицы стилей в Saxon нумерация выводится на немецком языке:

1
2
3
4
5
vier - Dodge
acht - Honda
dreizehn - Mercedes
vierzehn - Nash
siebzehn - Quantum

Если запросить комбинацию атрибутов format, ordinal и lang, не поддерживаемую процессором XSLT, процессор возвращается к стандартному поведению. Таблица стилей показывает, что делает Saxon при запросе нумерации на польском языке:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?xml version="1.0" ?>
<!-- number10.xsl -->
<xsl:stylesheet
  version="2.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
  <xsl:output method="text" />
  <xsl:template match="book">
    <xsl:for-each select=".//sect2">
      <xsl:number
        level="any"
        count="chapter|sect1|sect2|sect3"
        format="w - "
        lang="pl"
      />
      <xsl:value-of select="title" />
      <xsl:text>

      </xsl:text>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

Saxon не поддерживает польский язык, поэтому нумерация выводится на английском:

1
2
3
4
5
four - Dodge
eight - Honda
thirteen - Mercedes
fourteen - Nash
seventeen - Quantum

В последнем примере используются атрибуты format="๑" (тайская нумерация) и ordinal="yes":

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?xml version="1.0" ?>
<!-- number11.xsl -->
<xsl:stylesheet
  version="2.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
  <xsl:output method="html" />
  <xsl:template match="book">
    <html>
      <head>
        <title>Thai numbering</title>
      </head>
      <body style="font-family: sans-serif;">
        <h1>Thai numbering</h1>
        <p style="font-size: 150%">
          <xsl:for-each select=".//sect2">
            <xsl:number
              level="any"
              count="sect2"
              format="๑ "
            />
            <xsl:value-of select="title" />
            <br />
          </xsl:for-each>
        </p>
      </body>
    </html>
  </xsl:template>
</xsl:stylesheet>

Таблица стилей генерирует документ HTML, в котором элементы <sect2> нумеруются на тайском языке:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Thai numbering</title>
    </head>
    <body style="font-family: sans-serif;">
        <h1>Thai numbering</h1>
        <p style="font-size: 150%"> Dodge<br>
         Honda<br> Mercedes<br>
         Nash<br> Quantum<br></p>
    </body>
</html>

См. также

Ссылки

Комментарии