Как написать XSLT, чтобы процессор игнорировал комментарии при вычислении положения других элементов?
Я ожидаю, что XSLT-процессор будет отфильтровывать комментарии перед применением других правил шаблона, но с комментарием после последнего элемента списка тест not(position()=last()) не проходит.
Как я могу удалить комментарии перед этим тестом?
XML-ввод:
<?xml version = "1.0" encoding = "utf-8"?>
<html xmlns = "http://www.w3.org/1999/xhtml">
<ul>
<li>fish1</li>
<li>fish2</li>
<li>fish3</li>
<li>fish4</li>
<!--
<li>fish5</li>
-->
</ul>
</html>
XSLT:
<?xml version = "1.0" encoding = "utf-8"?>
<xsl:stylesheet
version = "2.0"
xmlns:xhtml = "http://www.w3.org/1999/xhtml"
xmlns:xsl = "http://www.w3.org/1999/XSL/Transform">
<xsl:output method = "text" encoding = "utf-8" indent = "no" />
<xsl:strip-space elements = "*" />
<xsl:template match = "comment()" />
<xsl:template match = "/">
<xsl:apply-templates />
</xsl:template>
<xsl:template match = "xhtml:ul">
<xsl:apply-templates />
</xsl:template>
<xsl:template match = "xhtml:li">
<xsl:apply-templates />
<xsl:if test = "not(position()=last())">
<xsl:text>, </xsl:text>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Вывод с SaxonJ-HE 12.1:
fish1, fish2, fish3, fish4,
Также обратите внимание, что XSLT 2 и более поздние версии имеют атрибут separator для xsl:value-of, поэтому самым простым подходом для желаемого вывода было бы использование, например. <xsl:template match = "xhtml:ul"><xsl:value-of select = "xhtml:li" separator = ", "/></xsl:template>. Не об ответе на игнорирование комментария, но, возможно, полезно.
А еще лучше сделать это <xsl:template match = "/xhtml:html"><xsl:value-of select = "xhtml:ul/xhtml:li" separator = ", "/></xsl:template>. Затем вы можете избавиться от всех других ваших шаблонов, не беспокоясь о том, что текст из какого-либо другого узла будет скопирован в вывод.
@musarithmia Я не понимаю, почему xsl:value-of не работает для вставки любой строки между элементами любой последовательности. Если ваш пример не отражает вашу реальную ситуацию, опубликуйте лучший. Предпочтительно в новом вопросе - я считаю, что на этот вопрос был дан ответ.
@musarithmia Не вижу смысла в этом обсуждении. Как вы говорите, ваш вопрос был об исключении узлов комментариев из обработанной последовательности, и по крайней мере 2 ответа ответили на него как таковые. Я все еще подозреваю, что xsl:value-of можно использовать для упрощения процесса, но без репрезентативного примера это все, что я могу сказать.





https://www.w3.org/TR/xslt20/#applying-templates:
Инструкция xsl:apply-templates принимает на вход последовательность узлов...
Значением по умолчанию атрибута select является child::node(), что вызывает обработку всех дочерних узлов узла контекста.
Чтобы исключить узел комментария из выбранной последовательности, измените это:
<xsl:template match = "xhtml:ul">
<xsl:apply-templates />
</xsl:template>
к:
<xsl:template match = "xhtml:ul">
<xsl:apply-templates select = "*" />
</xsl:template>
Обратите внимание, что вы можете удалить первые два шаблона.
Вы можете заменить test = "not(position()=last())" на test = "following-sibling::*".
У меня есть общее эмпирическое правило при написании XSLT, которое заключается в том, чтобы отдавать предпочтение написанию выражений XPath, а не написанию элементов XSLT (которых я стараюсь свести к минимуму). Применение этого правила к вашей таблице стилей даст что-то вроде этого:
<xsl:stylesheet
version = "2.0"
xmlns:xhtml = "http://www.w3.org/1999/xhtml"
xmlns:xsl = "http://www.w3.org/1999/XSL/Transform">
<xsl:output method = "text" encoding = "utf-8" indent = "no" />
<xsl:template match = "/">
<xsl:value-of select = "string-join(//xhtml:li, ', ')">
</xsl:template>
</xsl:stylesheet>
Возможности XSLT по созданию шаблонов и сопоставлению с образцом являются мощными, но в данном случае они намного мощнее, чем вам нужно.
Все, что вам действительно нужно здесь, это просто выражение XPath string-join(//xhtml:li, ', '), а XSLT, который я написал, — это просто простая оболочка для него.
Я склонен давать прямо противоположные советы. Здесь либо select='*', либо изменение теста Майклом было бы моим предпочтением. Проблема с использованием string-join заключается в том, что он будет игнорировать встроенную разметку в элементах списка (em, code, i, b, span и т. д.).
OP генерирует простой текст, поэтому другая разметка не имеет значения. Это одна из причин, по которой, на мой взгляд, решение «чистого XPath» является более подходящим.
Слишком часто я находил таблицы стилей, которые использовали этот подход, везде использовали выражения XPath и конструкции, такие как объединение строк, а потом кто-то говорил: «Эй, подождите, мы хотим, чтобы code или em или a были разрешены в этих местах». и теперь вы смотрите на утомительную работу по замене всех этих выражений. Используйте возможности XSLT в своих интересах, а не обходите их стороной :-)
ну, как оказалось, пример спрашивающего не совсем точно отражает их фактический случай, поэтому мое предложение не применимо. Но я думаю, что для случаев, когда люди действительно просто извлекают некоторые значения простого текста, мой предложенный подход действительно уместен; это вопрос признания, где это имеет место.
Это будет параметр парсера. Например, если вы пишете на Java, это будет
javax.xml.parsers.DocumentBuilderFactory#setIgnoringComments(true). Если вы используете XSLT-процессор с командной строкой, проверьте параметры этого процессора.