Почему XSLT выводит весь текст по умолчанию?

Привет, я выполнил преобразование, которое теряет тег, если оно равно null.

Я хотел проверить, работает ли мое преобразование нормально, поэтому вместо того, чтобы проверять его вручную, я написал еще один XSLT-код, который просто проверяет наличие этого конкретного тега в XML OUTPUT, если он является нулевым, а затем второй 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>

Он выводит все TEXT DATA, которые присутствуют в 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).

Ответ 1

почему предыдущий код выводит 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="shallow-skip"/> все несоответствующие узлы (включая текстовые узлы), а <xsl:mode on-no-match="fail"/> обрабатывает несоответствие как ошибку, а <xsl:mode warning-on-no-match="true"/> выдает предупреждение.

Ответ 2

В XSL существует несколько встроенных правил шаблонов, один из которых:

<xsl:template match="text()|@*">
  <xsl:value-of select="."/>
</xsl:template>

Он выводит текст.