为什么XSLT默认输出所有文本?

时间:2010-07-29 06:37:47

标签: xslt

您好我已经执行了一个转换,如果它为空,则会删除标记。

我想检查我的转换是否正常工作,因此我不再手动检查它,而是编写了一个XSLT代码,它只是检查OUTPUT XML中是否存在该特定标记,如果它是null,那么第二个XSLT应输出文本“FOUND”。 (我实际上并不需要一些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解析器)。

2 个答案:

答案 0 :(得分:145)

  

为什么前一个代码输出TEXT,   为什么我要坚持XSL忽略所有   其他文字?是的行为   所有XML解析器或仅我自己的

您正在发现规范中指定的最基本的XSLT功能之一:built-in templates of XSLT

来自the Spec

  

有一个内置的模板规则   允许递归处理继续   在没有成功模式的情况下   匹配显式模板规则   样式表。此模板规则   适用于两个元素节点和   根节点。以下显示了   相当于内置模板   规则:

<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添加

在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"/>会导致警告。

答案 1 :(得分:14)

XSL中有几个built in template rules,其中一个就是:

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

输出文字。