77

嗨,我已经执行了一个转换,如果它是空的,它会丢弃一个标签。

我想检查我的转换是否工作正常,所以我没有手动检查,而是编写了另一个 XSLT 代码,它只检查 OUTPUT 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 文件中存在的所有 TEXT DATA,

为避免这种情况,我不得不编写以下代码::

<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 解析器)。

4

2 回答 2

152

为什么以前的代码输出 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()"/>

命名空间节点的内置模板规则也是什么都不做。没有可以匹配命名空间节点的模式;因此,内置模板规则是唯一适用于命名空间节点的模板规则。

内置模板规则被视为在样式表之前隐式导入,因此其导入优先级低于所有其他模板规则。因此,作者可以通过包含显式模板规则来覆盖内置模板规则。

因此,报告的行为是应用内置模板的结果——这三个模板中的第一个和第二个。

用您自己的模板覆盖内置模板是一种很好的 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

Michael Kay 后来为 XSLT 3.0 添加的内容

xsl:mode在 XSLT 3.0 中,您可以在声明中指定回退行为,而不是添加包罗万象的模板规则。例如,<xsl:mode on-no-match="shallow-skip"/>导致所有不匹配的节点(包括文本节点)被跳过,而<xsl:mode on-no-match="fail"/>将不匹配视为错误,并<xsl:mode warning-on-no-match="true"/>导致警告。

于 2010-07-31T14:41:53.140 回答
14

XSL 中有几个内置的模板规则,其中之一是:

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

它输出文本。

于 2010-07-29T06:40:22.190 回答