Главная » XSLT » Вывод текста с нумерацией

0

Задача

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

Решение

Так как нумеровать можно по-разному, я в этом примере приведу ряд посте­пенно усложняющихся примеров, которые покрывают большую часть обычных (и ряд не столь обычных) потребностей в нумерации.

Нумерация братьев по порядку

Это самый простой вид нумерации. В примерах 7.37 и 7.38 показано, как вывести нумерованный список фамилий. Здесь я воспользовался элементом xsl:number и его атрибутом count. Атрибут count можно и опустить, так как по умолчанию нумеруются все узлы в текущем контексте.

Пример 7.37. Таблица стилей

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/

Transform">

<xsl:output method="text"/>

<xsl:template match="person">

<xsl:number count="*" format="1. "/> <xsl:value-of select="@name"/> </xsl:template>

Пример 7.28. Результат

1.     Al Zehtooney

2.     Brad York

3.     Charles Xavier

4.     David Willimas

5.     Edward Ulster

6.     Frank Townsend

7.     Greg Sutter

8.     Harry Rogers

9.     John Quincy

10.    Kent Peterson

Если нужно выровнять числа по правому краю, воспользуйтесь шаблоном из рецепта 7.3.

Начало нумерации не с 1

Стандартный элемент xsl:number позволяет начинать нумерацию только с 1 с увеличением тоже на 1, но небольшое ухищрение позволяет это легко испра­вить, см. примеры 7.39 и 7.40.

Пример 7.39. Таблица стилей для нумерации не по порядку

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:strip-space elements="*"/>

<xsl:template match="person"> <xsl:variable name="num">

<xsl:number count="*"/> </xsl:variable>

<xsl:number value="($num – 1) * 5 + 10" format="1. "/>

<xsl:value-of select="@name"/> <xsl:text>&#xa;</xsl:text> </xsl:template>

</xsl:stylesheet>

Пример 7.40. Результат

10.   Al Zehtooney

15.   Brad York

20.   Charles Xavier

25.   David Willimas

30.   Edward Ulster

35. Frank Townsend 40. Greg Sutter 45. Harry Rogers 50. John Quincy 55. Kent Peterson

Так можно поступать даже, если для нумерации применяются не числа. Ска­жем, в примерах 7.41 и 7.42 нумерация начинается с буквы L.

Пример 7.41. Таблица стилей для нумерации с буквы L

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:strip-space elements="*"/>

<xsl:template match="person"> <xsl:variable name="num">

<xsl:number count="*"/> </xsl:variable>

<xsl:number value="$num + 11" format="A. "/> <xsl:value-of select="@name"/> <xsl:text>&#xa;</xsl:text> </xsl:template>

</xsl:stylesheet>

Пример 7.42. Список фамилий, пронумерованных, начиная с буквы L

L. Al Zehtooney M. Brad York N. Charles Xavier O. David Willimas P. Edward Ulster Q. Frank Townsend R. Greg Sutter S. Harry Rogers T. John Quincy U. Kent Peterson

Глобальная нумерация элементов

Иногда нужно пронумеровать элементы по порядку, не обращая внимания на контекст. Типичный пример – нумерация концевых сносок. Сноски могут при­сутствовать на любом уровне в структуре документа, но нумероваться все равно

должны последовательно. Впрочем, продолжая уже начатую тему, рассмотрим документ, в котором люди распределены по группам и подгруппам:

<people> <group>

<person name="Al Zehtooney" age="33" sex="m" smoker="no"/> <person name="Brad York" age="38" sex="m" smoker="yes"/> <person name="Charles Xavier" age="32" sex="m" smoker="no"/> <person name="David Willimas" age="33" sex="m" smoker="no"/> <person name="Edward Ulster" age="33" sex="m" smoker="yes"/> <person name="Frank Townsend" age="35" sex="m" smoker="no"/> </group> <group>

<person name="Greg Sutter" age="40" sex="m" smoker="no"/> <person name="Harry Rogers" age="37" sex="m" smoker="no"/> <group>

<person name="John Quincy" age="43" sex="m" smoker="yes"/> <person name="Kent Peterson" age="31" sex="m" smoker="no"/> <person name="Larry Newell" age="23" sex="m" smoker="no"/> <group>

<person name="Max Milton" age="22" sex="m" smoker="no"/> <person name="Norman Lamagna" age="30" sex="m" smoker="no"/> <person name="Ollie Kensinton" age="44" sex="m" smoker="no"/> </group>

<person name="John Frank" age="24" sex="m" smoker="no"/> </group> <group>

<person name="Mary Williams" age="33" sex="f" smoker="no"/> <person name="Jane Frank" age="38" sex="f" smoker="yes"/> <person name="Jo Peterson" age="32" sex="f" smoker="no"/> <person name="Angie Frost" age="33" sex="f" smoker="no"/> <person name="Betty Bates" age="33" sex="f" smoker="no"/> <person name="Connie Date" age="35" sex="f" smoker="no"/> <person name="Donna Finster" age="20" sex="f" smoker="no"/> </group> <group>

<person name="Esther Gates" age="37" sex="f" smoker="no"/> <person name="Fanny Hill" age="33" sex="f" smoker="yes"/> <person name="Geta Iota" age="27" sex="f" smoker="no"/> <person name="Hillary Johnson" age="22" sex="f" smoker="no"/> <person name="Ingrid Kent" age="21" sex="f" smoker="no"/> <person name="Jill Larson" age="20" sex="f" smoker="no"/> <person name="Kim Mulrooney" age="41" sex="f" smoker="no"/> <person name="Lisa Nevins" age="21" sex="f" smoker="no"/>

</group> </group> </people>

Чтобы решить задачу, нужно лишь изменить атрибут level элемента xsl:number, присвоив ему значение "any". В этом случае процессор XSLT бу­дет при определении порядкового номера просматривать все вхождения элемента person. См. примеры 7.43 и 7.44.

Пример 7.43. Таблица стилей, в которой level = "any"

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/ Transform">

<xsl:output method="text"/> <xsl:strip-space elements="*"/>

<xsl:template match="person">

<xsl:number count="person" level="any" format="1. "/> <xsl:value-of select="@name"/> <xsl:text>&#xa;</xsl:text> </xsl:template>

</xsl:stylesheet>

Пример 7.44. Результат в случае, когда level = "any"

1.     Al Zehtooney

2.     Brad York

3.     Charles Xavier

4.     David Willimas

5.     Edward Ulster

6.     Frank Townsend

7.     Greg Sutter

8.     Harry Rogers

9.     John Quincy

10.    Kent Peterson

11.    Larry Newell

12.    Max Milton

13.    Norman Lamagna

14.    Ollie Kensinton

15.    John Frank

16.    Mary Williams

17.    Jane Frank

18.    Jo Peterson

19.    Angie Frost

20.    Betty Bates

21.    Connie Date

22.    Donna Finster

23.    Esther Gates

24.    Fanny Hill

25.    Geta Iota

26.    Hillary Johnson

27.    Ingrid Kent

28.    Jill Larson

29.    Kim Mulrooney

30.    Lisa Nevins

Глобальная нумерация элементов внутри подконтекста

Бывает, что нужно ограничить глобальную нумерацию конкретным контек­стом. Например, сопоставить каждому человеку номер внутри группы верхнего уровня, в которую он входит, игнорируя подгруппы.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:strip-space elements="*"/>

<xsl:template match="people/group"> <xsl:text>Группа </xsl:text>

<xsl:number count="group"/> <xsl:text>&#xa;</xsl:text> <xsl:apply-templates/> <xsl:text>&#xa;</xsl:text> </xsl:template>

<xsl:template match="person">

<xsl:number count="person" level="any" from="people/group" format="1. "/> <xsl:value-of select="@name"/> <xsl:text>&#xa;</xsl:text> </xsl:template>

</xsl:stylesheet>

Группа 1

1.     Al Zehtooney

2.     Brad York

3.     Charles Xavier

4.     David Willimas

5.     Edward Ulster

6.     Frank Townsend

Группа 2 1. Greg Sutter

2.     Harry Rogers

3.     John Quincy

4.     Kent Peterson

5.     Larry Newell

6.     Max Milton

7.     Norman Lamagna

8.     Ollie Kensinton

9.     John Frank

10.    Mary Williams

11.    Jane Frank

12.    Jo Peterson

13.    Angie Frost

14.    Betty Bates

15.    Connie Date

16.    Donna Finster

17.    Esther Gates

18.    Fanny Hill

19.    Geta Iota

20.    Hillary Johnson

21.    Ingrid Kent

22.    Jill Larson

23.    Kim Mulrooney

24.    Lisa Nevins

Иерархическая нумерация

В формальных и юридических документах нумерация часто производится с уче­том не только порядка следования, но и уровня в иерархии. В примере 7.45 демонст­рируется использование элемента xsl:number с атрибутом level="multiple".

Пример 7.45. Иерархическая нумерация людей с учетом группы

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:strip-space elements="*"/>

<xsl:template match="people/group"> <xsl:text>Группа </xsl:text> <xsl:number count="group"/> <xsl:text>&#xa;</xsl:text> <xsl:apply-templates/> <xsl:text>&#xa;</xsl:text> </xsl:template>

<xsl:template match="person">

<xsl:number count="group | person" level="multiple" format="1.1.1 "/>

<xsl:value-of select="@name"/> <xsl:text>&#xa;</xsl:text> </xsl:template>

</xsl:stylesheet>

Нумерация, реализованная в примере 7.45, выглядит странновато, но отра­жает результат применения атрибута count, когда level = "multiple". Атрибут count просто определяет, какие элементы-предки включать при фор­мировании иерархического номера. Таблица стилей присвоила людям номера в зависимости от группы и позиции элемента в этой группе. Так, Bard York по­лучил номер 1.2, поскольку он занимает вторую позицию в группе 1. Анало­гично, Max Milton идет под номером 2.3.4.1, так как он находится в группе 2, если учитывать только группы верхнего уровня, в группе 3 – если учитывать группы верхнего и второго уровня, и в группе 4 – если учитывать группы вер­хнего, второго и третьего уровня. И, наконец, в своей собственной группе он первый:

Группа 1

1.1    Al Zehtooney

1.2    Brad York

1.3    Charles Xavier

1.4    David Willimas

1.5    Edward Ulster

1.6    Frank Townsend

Группа 2

2.1    Greg Sutter

2.2    Harry Rogers

2.3.1  John Quincy

2.3.2  Kent Peterson

2.3.3  Larry Newell

2.3.4.1         Max Milton

2.3.4.2         Norman Lamagna

2.3.4.3         Ollie Kensinton

2.3.5 John Frank

2.4.1  Mary Williams

2.4.2  Jane Frank

2.4.3  Jo Peterson

2.4.4  Angie Frost

2.4.5  Betty Bates

2.4.6  Connie Date

2.4.7  Donna Finster

2.5.1  Esther Gates

2.5.2  Fanny Hill

2.5.3  Geta Iota

2.5.4  Hillary Johnson

2.5.5  Ingrid Kent

2.5.6  Jill Larson

2.5.7  Kim Mulrooney

2.5.8  Lisa Nevins

В типичном приложении ожидается такая схема нумерации, при котором но­мер на любом уровне соотносится с номером на предшествующем уровне. Этого можно достичь, применив несколько элементов xsl:number подряд, как показа­но в примерах 7.46 и 7.47.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www,w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:strip-space elements="*"/>

<xsl:template match="group"> <xsl:text>Гpyппa </xsl:text>

<xsl:number count="group" level="multiple"/> <xsl:text>&#xa;</xsl:text>

<xsl:apply-templates/> </xsl:template>

<xsl:template match="person">

<xsl:number count="group" level="multiple" format="1.1.1."/> <xsl:number count="person" level="single" format="1 "/>

<xsl:value-of select="@name"/> <xsl:text>&#xa;</xsl:text> </xsl:template>

</xsl:stylesheet>

Пример 7.47. Результат

Гpyппa 1

1.1    Al Zehtooney

1.2    Brad York

1.3    Charles Xavier

1.4    David Willimas

1.5    Edward Ulster

1.6    Frank Townsend ^уппа 2

2.1    Greg Sutter

2.2    Harry Rogers ^уппа 2.1

2.1.1  John Quincy

2.1.2  Kent Peterson

2.1.3  Larry Newell Группа 2.1.1

2.1.1.1         Max Milton

2.1.1.2         Norman Lamagna

2.1.1.3         Ollie Kensinton

2.1.4  John Frank Группа 2.2

2.2.1  Mary Williams

2.2.2  Jane Frank

2.2.3  Jo Peterson

2.2.4  Angie Frost

2.2.5  Betty Bates

2.2.6  Connie Date

2.2.7  Donna Finster Группа 2.3

2.3.1  Esther Gates

2.3.2  Fanny Hill

2.3.3  Geta Iota

2.3.4  Hillary Johnson

2.3.5  Ingrid Kent

2.3.6  Jill Larson

2.3.7  Kim Mulrooney

2.3.8  Lisa Nevins

Обсуждение

С помощью одного или нескольких элементов xsl:number с подходящими атрибутами можно реализовать почти любую схему нумерации. Однако чрезмер­ное употребление xsl:number (особенно с атрибутом level="multiple") может замедлить выполнение таблицы стилей. Для очень глубоких иерархий можно резко увеличить производительность, если передавать номер родите­ля дочернему элементу в качестве параметра. Посмотрите, как таким спосо­бом можно реализовать иерархическую нумерацию, вовсе не используя эле­мент xsl:number:

<xsl:stylesheet version="1. 0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:strip-space elements="*"/>

<xsl:template match="group">

<xsl:param name="parent-level" select=" ” "/>

<xsl:variable name="number" select="concat($parent-level,position())"/>

<xsl:text>Группа </xsl:text> <xsl:value-of select="$number"/> <xsl:text>&#xa;</xsl:text>

<xsl:apply-templates>

<xsl:with-param name="parent-level" select="concat($number,’.’)"/> </xsl:apply-templates>

</xsl:template>

<xsl:template match="person">

<xsl:param name="parent-level" select=" ” "/> <xsl:variable name="number">

<xsl:value-of select="concat($parent-level,position(),’ ‘)"/> </xsl:variable>

<xsl:value-of select="$number"/> <xsl:value-of select="@name"/> <xsl:text>&#xa;</xsl:text> </xsl:template>

</xsl:stylesheet>

Такое использование функции position() менее удобно, если нужна нуме­рация с помощью букв или римских цифр.

Мангано Сэл  XSLT. Сборник рецептов. – М.: ДМК Пресс, СПБ.: БХВ-Петербург, 2008. – 864 с.: ил.

По теме:

  • Комментарии