всей своей простоте и вычислительной мощи, рекурсия является гораздо более требовательной к ресурсам техникой программирования, чем обычная итеративная обработка. Поэтому всегда следует тщательно оценивать, во что может вылиться использование рекурсии. В любом случае следует избегать глубоких рекурсий (функций, количество рекурсивных вызовов в которых может быть большим) и рекурсий, неэкономно использующих память.
Кроме того, большинство действий, выполнение которых в 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. Результирующее множество выделено штриховкой.
Операция | Графическое представление | 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.) и публикуются с любезного разрешения авторов.
Перенос строк и элементы
Большинству читателей, скорее всего, хорошо знаком такой элемент языка HTML, как BR
, который используется для обозначения разрыва строки. В обычных текстовых файлах для той же самой цели используются символы с кодами #xA
, #xD
или их комбинации в зависимости от платформы. При совместном использовании неразмеченного текста и HTML часто возникает задача преобразования символов перевода строки в элементы BR
и наоборот.
Замену элемента BR
на текстовый узел, содержащий перевод строки, можно проиллюстрировать следующим тривиальным шаблоном.
<xsl:template match='BR'>
<xsl:text>
</xsl:text>
</xsl:template>