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

Inf*_*nd' 71 xslt xslt-2.0 xslt-1.0

嗨,我已经执行了一个转换,如果它是null,则删除一个标记.

我想检查我的转换是否正常工作,所以不是手动检查,而是编写了一个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>
Run Code Online (Sandbox Code Playgroud)

它输出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>
Run Code Online (Sandbox Code Playgroud)

为什么以前的代码输出TEXT,为什么我要坚持XSL忽略所有其他文本?是所有XML解析器的行为或仅我自己的行为(我正在使用msxml解析器).

Dim*_*hev 146

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

您正在发现规范中指定的最基本的XSLT功能之一:XSLT的内置模板.

规格:

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

<xsl:template match="*|/">
  <xsl:apply-templates/>
</xsl:template>
Run Code Online (Sandbox Code Playgroud)

每种模式还有一个内置模板规则,它允许递归处理在样式表中的显式模板规则没有成功模式匹配的情况下以相同模式继续.此模板规则适用于元素节点和根节点.以下显示模式m的内置模板规则的等效项.

<xsl:template match="*|/" mode="m">
  <xsl:apply-templates mode="m"/>
</xsl:template>
Run Code Online (Sandbox Code Playgroud)

还有一个用于文本和属性节点的内置模板规则,用于复制文本:

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

用于处理指令和注释的内置模板规则是什么都不做.

<xsl:template match="processing-instruction()|comment()"/>
Run Code Online (Sandbox Code Playgroud)

命名空间节点的内置模板规则也不做任何事情.没有可以匹配命名空间节点的模式; 因此,内置模板规则是应用于命名空间节点的唯一模板规则.

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

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

使用您自己的模板覆盖内置模板是一个很好的XSLT设计模式,只要调用它就会发出错误消息,以便程序员立即知道他的转换是"泄漏":

例如,如果有这个XML文档:

<a>
  <b>
    <c>Don't want to see this</c>
  </b>
</a>
Run Code Online (Sandbox Code Playgroud)

并通过此转换处理:

<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>
Run Code Online (Sandbox Code Playgroud)

结果是:

<a name="a">
   <b name="b">Don't want to see this</b>
</a>
Run Code Online (Sandbox Code Playgroud)

并且程序员将非常混淆不需要的文本是如何出现的.

但是,添加此项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>
Run Code Online (Sandbox Code Playgroud)

现在,除了令人困惑的输出之外,程序员还会收到警告,立即解释问题:

 WARNING: Unmatched element: c
Run Code Online (Sandbox Code Playgroud)

后来由Michael Kay为XSLT 3.0添加

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

  • +1:很好的解释 - 比接受的答案更完整,尽管接受的答案也回答了具体的问题. (4认同)
  • 你...完整的信息:)非常感谢你:) (2认同)

Ode*_*ded 14

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

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

它输出文字.