Гораздо сложнее написать шаблон, делающий обратную операцию, — замену символов переноса строки на элементы 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)'/>
<!-- ... -->
Для того же, чтобы заменить
<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>
Результат его выполнения будет иметь следующий вид:
<pre>One little rabbit<BR/>
Two little rabbits<BR/>
Three little rabbits</pre>
Данные, разделенные запятыми (CSV)
Рекурсивную методику замены, которую мы представили выше, можно использовать для того, чтобы разметить данные, разделенные запятыми (или CSV, comma-separated values). CSV — это старый простой формат представления данных, в котором они просто перечисляются через запятую, например:
a, b, с, d, e, f, g
и так далее. Формат CSV был одним из первых шагов к созданию языков разметки: данные в нем
Покажем на простом примере, как можно преобразовать CSV-данные в XML-документ. Пусть входящий документ выглядит как:
<data>a, b, с, d, e, f</data>
Для того чтобы решение было как можно более общим, вынесем создание XML-разметки для каждого из элементов этой последовательности в отдельный шаблон:
<xsl:template name='item'>
<xsl:param name='item'/>
<item><xsl:copy-of select='$item'/></item>
</xsl:template>
Тогда головной размечающий шаблон запишется в виде.
<xsl:template name='markup' match='text()' mode='CSV'>
<xsl:param name='str' select='.'/>
<xsl:param name='delimiter' select='',''/>
<xsl:choose>
<xsl:when test='contains($str,$delimiter)'>
<xsl:call-template name='item'>
<xsl:with-param name='item'
select='substring-before($str, $delimiter)'/>
</xsl:call-template>
<xsl:call-template name='markup'>
<xsl:with-param name='str'