Выбрать главу

<xsclass="underline" variable name="set" select="document('')//node()"/>

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

<xsclass="underline" for-each select="$set[position() &lt;= $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 на текстовый узел, содержащий перевод строки, можно проиллюстрировать следующим тривиальным шаблоном.

Листинг 11.16. Шаблон замены элементов BR на перенос строки

<xsclass="underline" template match="BR">

 <xsclass="underline" text>&#xA;</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)"/>

<!-- ... -->

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

Листинг 11.17. Шаблон для замены подстроки в строке

<xsclass="underline" template name="replace" match="text()" mode="replace">

 <xsclass="underline" param name="str" select="."/>

 <xsclass="underline" param name="search-for" select="'&#xA;'"/>

 <xsclass="underline" param name="replace-with">

  <xsclass="underline" element name="BR"/>

  <xsclass="underline" text>&#xA;</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 и следующий за ним перенос строки, добавленный для лучшей читаемости.

В качестве примера отформатируем содержание следующего элемента: