Алексей Валиков - Технология XSLT
<xsl:if test="$i < $n">
<option>
<xsl:value-of select="$i"/>
</option>
<xsl:call-template name="for">
<xsl:with-param name="i" select="$i + 1"/>
<xsl:with-param name="n" select="$n"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Листинг 11.15 Выходящий документ<option>0</option>
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
<option>5</option>
<option>6</option>
<option>7</option>
<option>8</option>
<option>9</option>
Пожалуй, этим примером мы и закончим рассмотрение рекурсии. Осталось лишь добавить, что при всей своей простоте и вычислительной мощи, рекурсия является гораздо более требовательной к ресурсам техникой программирования, чем обычная итеративная обработка. Поэтому всегда следует тщательно оценивать, во что может вылиться использование рекурсии. В любом случае следует избегать глубоких рекурсий (функций, количество рекурсивных вызовов в которых может быть большим) и рекурсий, неэкономно использующих память.
Кроме того, большинство действий, выполнение которых в XSLT затруднено, в классических языках программирования выполняется, как правило, намного легче и эффективней. Поэтому, каждый раз, когда стоит вопрос об использовании рекурсии, наряду с ней следует рассматривать такую альтернативу, как использование расширений XSLT, написанных на обычном императивном языке.
Метод Пиза для for-цикла
Для простых for-циклов, которые должны выполниться строго определенное число раз, вместо рекурсии можно использовать весьма остроумный метод, предложенный Венделлом Пизом (Wendell Piez, Mullberry Technologies, Inc). Суть метода состоит в том, что хоть мы и не можем сгенерировать множество узлов, выбрать множество с определенным количеством узлов нам вполне по силам.
Для начала выберем какое-нибудь множество узлов документа преобразования:
<xsl:variable name="set" select="document('')//node()"/>
Затем для повторения определенных действий несколько раз используем конструкцию вида
<xsl:for-each select="$set[position() <= $number]">
<!-- Действия -->
</xsl:for-each>
где number указывает требуемое число итераций.
При использовании метода Пиза следует учитывать следующие особенности.
□ Множество узлов set не должно быть слишком большим — иначе его выбор будет неэффективным.
□ Множество узлов set обязательно должно содержать число итераций (number) узлов.
В целом же метод Пиза — классический пример эффективного применения инструментов не по назначению.
Операции над множествами
Рассматривая такой тип данных, как множества узлов, мы отмечали ограниченность операций, которые можно с ними производить. В частности, XSLT не предоставляет стандартных операторов для определения принадлежности одного множества другому, нахождения пересечений, разности множеств и так далее. Возможности, которые были представлены при описании этого типа данных, основанные на использовании оператора равенства, на самом деле реализуют далеко не математические операции над множествами.
В этом разделе мы рассмотрим иной подход к реализации операций над множествами, основанный на очень простом определении принадлежности узла множеству. Узел node принадлежит множеству nodeset тогда и только тогда, когда выполняется равенство
count($nodeset) = count($node | $nodeset)
Учитывая это обстоятельство, операции над множествами можно представить, как показано в табл. 11.1. Результирующее множество выделено штриховкой.
Таблица 11.1. Операции над множествами
Операция Графическое представление XPath-выражение Объединение $A | $B Пересечение $А[count(.|$B)=count($B)] Разность $A[count(.|$B)!=count($B)] Симметрическая разность $A[count(.|$B)!=count($B)] | $B[count(.|$A)!=count($A)]Приведенные выше методы были разработаны Майклом Кеем (Michael Kay, Software AG), Оливером Беккером (Oliver Becker, Humboldt-Universitat zu Berlin), Кеном Холманом (Ken Holman, Crane Softwrights Ltd.) и публикуются с любезного разрешения авторов.
Перенос строк и элементы BR
Большинству читателей, скорее всего, хорошо знаком такой элемент языка HTML, как BR, который используется для обозначения разрыва строки. В обычных текстовых файлах для той же самой цели используются символы с кодами #xA, #xD или их комбинации в зависимости от платформы. При совместном использовании неразмеченного текста и HTML часто возникает задача преобразования символов перевода строки в элементы BR и наоборот.
Замену элемента BR на текстовый узел, содержащий перевод строки, можно проиллюстрировать следующим тривиальным шаблоном.
Листинг 11.16. Шаблон замены элементов BR на перенос строки<xsl:template match="BR">
<xsl:text>
</xsl:text>
</xsl:template>
Гораздо сложнее написать шаблон, делающий обратную операцию, — замену символов переноса строки на элементы BR. В XSLT нет встроенного механизма для замены подстроки в строке (тем более на элемент), поэтому нам придется создать для этой цели собственный шаблон.
Для этой цели мы можем воспользоваться функциями substring-before и substring-after. Функция substring-before($str, $search-for) возвратит часть строки str, которая предшествует первому вхождению в нее подстроки search-for, а функция substring-after($str, $search-for) — последующую часть. То есть заменить первое вхождение можно шаблоном вида
<!-- ... -->
<xsl:value-of select = "substring-before($str, $search-for)"/>
<xsl:copy-of select = "$replace-with"/>
<xsl:value-of select = "substring-after($str, $search-for)"/>
<!-- ... -->
Для того же, чтобы заменить все вхождения, достаточно рекурсивно повторить операцию замены первого вхождения с той частью строки, которая следует за ним. Приведем шаблон, который выполняет эту операцию.
Листинг 11.17. Шаблон для замены подстроки в строке<xsl:template name="replace" match="text()" mode="replace">
<xsl:param name="str" select="."/>
<xsl:param name="search-for" select="'
'"/>
<xsl:param name="replace-with">
<xsl:element name="BR"/>
<xsl:text>
</xsl:text>
</xsl:param>
<xsl:choose>
<xsl:when test="contains($str, $search-for)">
<xsl:value-of select="substring-before($str, $search-for)"/>
<xsl:copy-of select="$replace-with"/>
<xsl:call-template name="replace">
<xsl:with-param name="str"
select="substring-after($str, $search-for)"/>
<xsl:with-param name="search-for" select="$search-for"/>
<xsl:with-param name="replace-with " select="$replace-with"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$str"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Шаблон, приведенный в этом листинге, может быть вызван двумя способами: элементом xsl:apply-templates в режиме replace (в этом случае он будет обрабатывать текстовые узлы выбранного множества), или при помощи именного вызова элементом xsl:call-template. Шаблон принимает на вход три параметра.
□ Параметр str, содержащий строку, в которой нужно произвести замену. По умолчанию этому параметру присваивается текстовое значение текущего узла.
□ Параметр search-for, содержащий подстроку, которую требуется найти и заменить в строке str. По умолчанию замене будут подлежать символы переноса строки, "&#хА;".
□ Параметр replace-with, содержащий объект, на который следует заменять подстроки search-for. По умолчанию эти подстроки будут заменяться на элемент BR и следующий за ним перенос строки, добавленный для лучшей читаемости.
В качестве примера отформатируем содержание следующего элемента:
<pre>One little rabbit
Two little rabbits
Three little rabbits</pre>
Запишем шаблон для обработки элемента pre:
<xsl:template match="pre">
<xsl:copy>
<xsl:apply-templates mode="replace"/>
</xsl:copy>
</xsl:template>
Результат его выполнения будет иметь следующий вид:
Откройте для себя мир чтения на siteknig.com - месте, где каждая книга оживает прямо в браузере. Здесь вас уже ждёт произведение Алексей Валиков - Технология XSLT, относящееся к жанру Программирование. Никаких регистраций, никаких преград - только вы и история, доступная в полном формате. Наш литературный портал создан для тех, кто любит комфорт: хотите читать с телефона - пожалуйста; предпочитаете ноутбук - идеально! Все книги открываются моментально и представлены полностью, без сокращений и скрытых страниц. Каталог жанров поможет вам быстро найти что-то по настроению: увлекательный роман, динамичное фэнтези, глубокую классику или лёгкое чтение перед сном. Мы ежедневно расширяем библиотеку, добавляя новые произведения, чтобы вам всегда было что открыть "на потом". Сегодня на siteknig.com доступно более 200000 книг - и каждая готова стать вашей новой любимой. Просто выбирайте, открывайте и наслаждайтесь чтением там, где вам удобно.


