<xsclass="underline" variable name="set" select="document('')//node()"/>
Затем для повторения определенных действий несколько раз используем конструкцию вида
<xsclass="underline" for-each select="$set[position() <= $number]">
<!-- Действия -->
</xsclass="underline" 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
на текстовый узел, содержащий перевод строки, можно проиллюстрировать следующим тривиальным шаблоном.
<xsclass="underline" template match="BR">
<xsclass="underline" text>
</xsclass="underline" text>
</xsclass="underline" template>
Гораздо сложнее написать шаблон, делающий обратную операцию, — замену символов переноса строки на элементы BR. В XSLT нет встроенного механизма для замены подстроки в строке (тем более на элемент), поэтому нам придется создать для этой цели собственный шаблон.
Для этой цели мы можем воспользоваться функциями substring-before
и substring-after
. Функция substring-before($str, $search-for)
возвратит часть строки str
, которая предшествует первому вхождению в нее подстроки search-for
, а функция substring-after($str, $search-for)
— последующую часть. То есть заменить первое вхождение можно шаблоном вида
<!-- ... -->
<xsclass="underline" value-of select = "substring-before($str, $search-for)"/>
<xsclass="underline" copy-of select = "$replace-with"/>
<xsclass="underline" value-of select = "substring-after($str, $search-for)"/>
<!-- ... -->
Для того же, чтобы заменить все вхождения, достаточно рекурсивно повторить операцию замены первого вхождения с той частью строки, которая следует за ним. Приведем шаблон, который выполняет эту операцию.
<xsclass="underline" template name="replace" match="text()" mode="replace">
<xsclass="underline" param name="str" select="."/>
<xsclass="underline" param name="search-for" select="'
'"/>
<xsclass="underline" param name="replace-with">
<xsclass="underline" element name="BR"/>
<xsclass="underline" text>
</xsclass="underline" text>
</xsclass="underline" param>
<xsclass="underline" choose>
<xsclass="underline" when test="contains($str, $search-for)">
<xsclass="underline" value-of select="substring-before($str, $search-for)"/>
<xsclass="underline" copy-of select="$replace-with"/>
<xsclass="underline" call-template name="replace">
<xsclass="underline" with-param name="str"
select="substring-after($str, $search-for)"/>
<xsclass="underline" with-param name="search-for" select="$search-for"/>
<xsclass="underline" with-param name="replace-with " select="$replace-with"/>
</xsclass="underline" call-template>
</xsclass="underline" when>
<xsclass="underline" otherwise>
<xsclass="underline" value-of select="$str"/>
</xsclass="underline" otherwise>
</xsclass="underline" choose>
</xsclass="underline" template>
Шаблон, приведенный в этом листинге, может быть вызван двумя способами: элементом xsclass="underline" apply-templates
в режиме replace
(в этом случае он будет обрабатывать текстовые узлы выбранного множества), или при помощи именного вызова элементом xsclass="underline" call-template
. Шаблон принимает на вход три параметра.
□ Параметр str
, содержащий строку, в которой нужно произвести замену. По умолчанию этому параметру присваивается текстовое значение текущего узла.
□ Параметр search-for
, содержащий подстроку, которую требуется найти и заменить в строке str
. По умолчанию замене будут подлежать символы переноса строки, "&#хА;
".
□ Параметр replace-with
, содержащий объект, на который следует заменять подстроки search-for
. По умолчанию эти подстроки будут заменяться на элемент BR
и следующий за ним перенос строки, добавленный для лучшей читаемости.
В качестве примера отформатируем содержание следующего элемента: