Почему XSLT выводит весь текст по умолчанию?
Привет, я выполнил преобразование, которое удаляет тег, если он пуст.
Я хотел проверить, нормально ли работает мое преобразование, поэтому вместо проверки вручную я написал еще один код XSLT, который просто проверяет наличие этого конкретного тега в OUTPUT XML, если он равен NULL, то второй XSLT должен вывести текст "НАЙДЕН". (На самом деле мне не нужны какие-то XML-данные, но я просто использую XSLT для поиска.)
Когда я попробовал с этим кодом XSL::
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/SiebelMessage//SuppressCalendar[.!='']">
FOUND
</xsl:template>
</xsl:stylesheet>
Он выводит все текстовые данные, которые присутствуют в файле XML,
чтобы избежать этого, я должен был написать этот код:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/SiebelMessage//SuppressCalendar[.!='']">
FOUND
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
почему предыдущий код выводит TEXT, почему я должен настаивать на том, чтобы XSL игнорировал весь другой текст? является то, что поведение всех парсеров XML или только мой собственный (я использую парсер msxml).
2 ответа
почему предыдущий код выводит TEXT, почему я должен настаивать на том, чтобы XSL игнорировал весь другой текст? является то, что поведение всех парсеров XML или только мой собственный
Вы обнаруживаете одну из самых фундаментальных функций XSLT, как указано в Спецификации: встроенные шаблоны XSLT.
Из спецификации:
Существует встроенное шаблонное правило, позволяющее продолжить рекурсивную обработку при отсутствии успешного сопоставления с образцом с помощью явного шаблонного правила в таблице стилей. Это шаблонное правило применяется как к узлам элемента, так и к корневому узлу. Ниже показан эквивалент встроенного правила шаблона:
<xsl:template match="*|/"> <xsl:apply-templates/> </xsl:template>
Существует также встроенное правило шаблона для каждого режима, которое позволяет продолжить рекурсивную обработку в том же режиме при отсутствии успешного сопоставления с образцом с помощью явного правила шаблона в таблице стилей. Это шаблонное правило применяется как к узлам элемента, так и к корневому узлу. Ниже показан эквивалент встроенного правила шаблона для режима m.
<xsl:template match="*|/" mode="m"> <xsl:apply-templates mode="m"/> </xsl:template>
Существует также встроенное шаблонное правило для узлов текста и атрибутов, которое копирует текст через:
<xsl:template match="text()|@*"> <xsl:value-of select="."/> </xsl:template>
Встроенное шаблонное правило для обработки инструкций и комментариев - ничего не делать.
<xsl:template match="processing-instruction()|comment()"/>
Встроенное шаблонное правило для узлов пространства имен также ничего не делает. Нет шаблона, который мог бы соответствовать узлу пространства имен; таким образом, встроенное шаблонное правило является единственным шаблонным правилом, которое применяется к узлам пространства имен.
Встроенные правила шаблона обрабатываются так, как если бы они были импортированы неявно перед таблицей стилей и поэтому имеют более низкий приоритет импорта, чем все другие правила шаблона. Таким образом, автор может переопределить встроенное шаблонное правило, включив явное шаблонное правило.
Итак, сообщаемое поведение является результатом применения встроенных шаблонов - 1-го и 2-го из всех трех.
Это хороший шаблон проектирования XSLT для переопределения встроенных шаблонов своими собственными, которые при каждом вызове будут выдавать сообщение об ошибке, так что программист сразу узнает, что его преобразование "протекает":
Например, если есть этот документ XML:
<a>
<b>
<c>Don't want to see this</c>
</b>
</a>
и это обрабатывается с помощью этого преобразования:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="a|b">
<xsl:copy>
<xsl:attribute name="name">
<xsl:value-of select="name()"/>
</xsl:attribute>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
результат:
<a name="a">
<b name="b">Don't want to see this</b>
</a>
и программист будет сильно смущен тем, как появился нежелательный текст.
Тем не менее, просто добавив этоcatch-all template
помогает избежать такой путаницы и сразу же выявлять ошибки:
<xsl:template match="*">
<xsl:message terminate="no">
WARNING: Unmatched element: <xsl:value-of select="name()"/>
</xsl:message>
<xsl:apply-templates/>
</xsl:template>
Теперь, помимо сбивающего с толку вывода, программист получает предупреждение, которое немедленно объясняет проблему:
WARNING: Unmatched element: c
Позднее добавление Майкл Кей для XSLT 3.0
В XSLT 3.0 вместо добавления универсального правила шаблона вы можете указать резервное поведение для xsl:mode
декларация. Например, <xsl:mode on-no-match="shallow-skip"/>
приводит к пропуску всех узлов, которые не совпадают (включая текстовые узлы), в то время как <xsl:mode on-no-match="fail"/>
обрабатывает несоответствие как ошибку, и <xsl:mode warning-on-no-match="true"/>
приводит к предупреждению.
В XSL есть несколько встроенных шаблонных правил, одно из которых таково:
<xsl:template match="text()|@*">
<xsl:value-of select="."/>
</xsl:template>
Это выводит текст.