Почему XSLT выводит весь текст по умолчанию? - PullRequest
71 голосов
/ 29 июля 2010

Привет! Я выполнил преобразование, которое удаляет тег, если он нулевой.

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

145 голосов
/ 31 июля 2010

почему предыдущий код выводит 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"/> приводит к предупреждению.

14 голосов
/ 29 июля 2010

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

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

Выводит текст.

...