#xslt #xslt-1.0
#xslt #xslt-1.0
Вопрос:
Если содержимое citations
узла выглядит примерно так:
<p>
WAJWAJADS:
</p>
<p>
asdf
</p>
<p>
ALSOAS:
</p>
<p>
lorem ipsum...<br />
lorem<br />
blah blah <i>
adfas amp;amp; dasdsaafs
</i>, April 2011.<br />
lorem lorem dear lord the whitespace
</p>
Есть ли какой-либо способ преобразовать это в правильно отформатированный HTML с помощью XSLT?
normalize-space()
просто объединяет все вместе. Лучшее, что мне удалось сделать, это normalize-space()
для всех p
потомков в for-each
цикле и обернуть их в p
элемент. Однако тогда все внутренние теги все равно теряются.
Есть ли лучший способ проанализировать это сгенерированное WYSIWYG крушение поезда? К сожалению, я не могу контролировать сгенерированный XML.
Комментарии:
1. Каково ваше определение «правильно отформатированного HTML»?
2. Нет дополнительных пробелов между началом / концом узла и текстом.
Ответ №1:
Я немного изменил ответ Мартина Хоннена:
<xsl:template match="text()">
<xsl:value-of select="normalize-space(.)"/>
<xsl:if test="substring(., string-length(.)) = ' ' and substring(., string-length(.) - 1, string-length(.)) != ' '">
<xsl:text> </xsl:text>
</xsl:if>
</xsl:template>
он проверяет, является ли последний символ пробелом, а последние 2 символа не являются пробелами, если true, он вставляет пробел.
Ответ №2:
Сначала вам нужно иметь правильно сформированный XML-файл с корнем.
Предполагая, что у вас это есть, вы можете применить преобразование идентификатора для копирования исходного дерева в результат, разделять пробелы между тегами, при необходимости генерировать выходные данные в формате HTML (без объявления XML) с отступом и использовать normalize-space()
только в текстовых узлах.
Попробуйте эту таблицу стилей:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:strip-space elements="*"/>
<xsl:output indent="yes" method="html"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="text()">
<xsl:value-of select="normalize-space(.)"/>
</xsl:template>
</xsl:stylesheet>
Результат, примененный к предоставленным вами данным, будет:
<p>WAJWAJADS:</p>
<p>asdf</p>
<p>ALSOAS:</p>
<p>lorem ipsum...<br>lorem<br>blah blah<i>adfas amp;amp; dasdsaafs</i>, April 2011.<br>lorem lorem dear lord the whitespace
</p>
Вы можете увидеть результат, примененный к вашему примеру в этом скрипте XSLT
ОБНОВЛЕНИЕ 1: чтобы добавить дополнительный пробел вокруг каждого текстового узла (и избежать конкатенации при вычислении строкового значения узла), вы можете заменить последний шаблон на:
<xsl:template match="text()">
<xsl:value-of select="concat(' ',normalize-space(.),' ')"/>
</xsl:template>
Результат:
<html>
<p> WAJWAJADS: </p>
<p> asdf </p>
<p> ALSOAS: </p>
<p> lorem ipsum... <br> lorem <br> blah blah <i> adfas amp;amp; dasdsaafs </i> , April 2011. <br> lorem lorem dear lord the whitespace
</p>
</html>
См.: http://xsltransform.net/3NzcBsE/1
ОБНОВЛЕНИЕ 2: добавление пробела или новой строки после каждого скопированного элемента. Поместите это <xsl:text>amp;#xa;</xsl:text>
(для новой строки) или это <xsl:text> </xsl:text>
(для пробела) после </xsl:copy>
в первом шаблоне:
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
<xsl:text>amp;#xa;</xsl:text>
</xsl:template>
Результат:
<html>
<p>WAJWAJADS:</p>
<p>asdf</p>
<p>ALSOAS:</p>
<p>lorem ipsum...<br>
lorem<br>
blah blah<i>adfas amp;amp; dasdsaafs</i>
, April 2011.<br>
lorem lorem dear lord the whitespace
</p>
</html>
Комментарии:
1. Не могли бы вы объяснить значение
@*|node()
в своем ответе?2. То
@
жеattribute::
самое, что и , что означает ось атрибутов.@*
илиattribute::*
означает любой атрибут.node()
соответствует любому узлу, кроме атрибутов и пространств имен (он соответствует элементам, текстовым узлам, комментариям и инструкциям по обработке).|
Это оператор объединения. Конечное выражение соответствует атрибутам или любому тексту, комментарию, инструкции по обработке или элементу.3.
<xsl:copy>
Просто копирует соответствующий узел.<xsl:apply-templates/>
Внутренняя<xsl:copy>
часть также должна быть явно настроена на выбор атрибутов, поскольку по умолчанию они не выбираются.4. Как вы можете видеть в своей скрипке, проблема связана с внутренними элементами, такими как
i
. Изnormalize-space()
-за текстового содержимого эти элементы смешиваются вместе с родительским текстом.5. Это можно компенсировать добавлением пробела перед и после каждого текстового узла:
<xsl:value-of select="concat(' ',normalize-space(.),' ')"/>
. См.: xsltransform.net/3NzcBsE/1
Ответ №3:
Используйте шаблон преобразования идентификатора плюс шаблон для текстовых узлов, выполняющих нормализацию пространства:
<xsl:template match="text()"><xsl:value-of select="normalize-space()"/></xsl:template>
Ответ №4:
Этот вопрос было бы намного проще понять, если бы пример содержал реальный текст вместо тарабарщины. «Нет дополнительных пробелов между началом / концом узла и текстом». недостаточно точное описание ожидаемого результата.
Я собираюсь сделать предположение здесь и предположить, что вы действительно хотите выполнить операцию «от пробелов до одного пробела» для всех текстовых узлов. Это можно сделать следующим образом:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="text()" priority="1">
<xsl:variable name="temp" select="normalize-space(concat('x', ., 'x'))" />
<xsl:value-of select="substring($temp, 2, string-length($temp) - 2)"/>
</xsl:template>
</xsl:stylesheet>
При применении к следующему тестовому вводу:
<chapter>
<p>
This question would have
been a lot <b> easier </b> to understand
if the example contained
<i> real </i> text instead of
gibberish.
</p>
<p>
Here is an example of preserving zero spaces
between text nodes:<br/>(continued) on a new line.
</p>
<p>
Here is another example of
preserving zero spaces within a text
node: <i>some text in italic</i> followed
by normal text.
</p>
</chapter>
результатом будет:
<?xml version="1.0" encoding="UTF-8"?>
<chapter>
<p> This question would have been a lot <b> easier </b> to understand if the example contained <i> real </i> text instead of gibberish. </p>
<p> Here is an example of preserving zero spaces between text nodes:<br/>(continued) on a new line. </p>
<p> Here is another example of preserving zero spaces within a text node: <i>some text in italic</i> followed by normal text. </p>
</chapter>
—
Обратите внимание, что при отображении в HTML не будет разницы между вводом и выводом.