为什么 XSLT 默认输出所有文本? [英] Why does XSLT output all text by default?

查看:25
本文介绍了为什么 XSLT 默认输出所有文本?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我执行了一个转换,如果它为空,则会删除一个标签.

我想检查我的转换是否工作正常,所以我没有手动检查它,而是编写了另一个 XSLT 代码,它只检查 OUTPUT XML 中该特定标记的存在,如果它为空,则第二个 XSLT应该输出一个文本找到".(我实际上并不需要某种 XML 类型的输出,但我只是使用 XSLT 进行搜索.)

当我尝试使用此 XSL 代码时 ::

<xsl:template match="/SiebelMessage//SuppressCalendar[.!='']">成立</xsl:模板></xsl:stylesheet>

它输出 XML 文件中存在的所有文本数据,

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

<xsl:template match="/SiebelMessage//SuppressCalendar[.!='']">成立</xsl:模板><xsl:template match="text()"/></xsl:stylesheet>

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

解决方案

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

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

来自规范:

<块引用>

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

<xsl:apply-templates/></xsl:模板>

还有一个内置的模板规则对于每种模式,允许递归处理以继续相同没有成功的模式通过显式模板进行模式匹配样式表中的规则.这个模板规则适用于元素节点和根节点.下面显示的是相当于内置模板模式 m 的规则.

<xsl:apply-templates mode="m"/></xsl:模板>

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

<xsl:value-of select="."/></xsl:模板>

内置模板规则处理说明和注释就是什么都不做.

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

内置的模板规则是将它们视为进口隐含在样式表之前和所以进口优先级低于所有其他模板规则.就这样作者可以覆盖一个内置的通过包含显式的模板规则模板规则.

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

用您自己的模板覆盖内置模板是一种很好的 XSLT 设计模式,每次调用时都会发出错误消息,以便程序员立即知道他的转换正在泄漏":>

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

<b><c>不想看到这个</c></b></a>

并通过此转换进行处理:

<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:模板></xsl:stylesheet>

结果是:

<b name="b">不想看到这个</b></a>

程序员会很困惑不想要的文本是如何出现的.

但是,只需添加此catch-all 模板有助于避免任何此类混淆并立即捕获错误:

 <xsl:message terminate="no">警告:不匹配的元素:<xsl:value-of select="name()"/></xsl:message><xsl:apply-templates/></xsl:模板>

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

 警告:不匹配的元素: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"/> 导致警告.

Hi I had performed a transformation which drops a tag if it is null.

I wanted to check whether my transformation is working fine, so instead of checking it manually, I wrote one more XSLT code which just checks the presence of that particular tag in the OUTPUT XML, if it is null, then the second XSLT should output a text "FOUND". (I don't actually need some XML kind of output but I am just using XSLT for searching.)

When I tried with this XSL code ::

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/SiebelMessage//SuppressCalendar[.!='']">
      FOUND
  </xsl:template>
</xsl:stylesheet>

It outputs all the TEXT DATA that is present in the XML file,

to avoid that, I had to write this code::

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

why did the former code outputs TEXT, why should I insist XSL to ignore all other text? is that the behavior of all XML parsers or only of my own (I am using msxml parser).

解决方案

why did the former code outputs TEXT, why should I insist XSL to ignore all other text? is that the behavior of all XML parsers or only of my own

You are discovering one of the most fundamental XSLT features as specified in the Specification: the built-in templates of XSLT.

From the Spec:

There is a built-in template rule to allow recursive processing to continue in the absence of a successful pattern match by an explicit template rule in the stylesheet. This template rule applies to both element nodes and the root node. The following shows the equivalent of the built-in template rule:

<xsl:template match="*|/">
  <xsl:apply-templates/>
</xsl:template>

There is also a built-in template rule for each mode, which allows recursive processing to continue in the same mode in the absence of a successful pattern match by an explicit template rule in the stylesheet. This template rule applies to both element nodes and the root node. The following shows the equivalent of the built-in template rule for mode m.

<xsl:template match="*|/" mode="m">
  <xsl:apply-templates mode="m"/>
</xsl:template>

There is also a built-in template rule for text and attribute nodes that copies text through:

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

The built-in template rule for processing instructions and comments is to do nothing.

<xsl:template match="processing-instruction()|comment()"/>

The built-in template rule for namespace nodes is also to do nothing. There is no pattern that can match a namespace node; so, the built-in template rule is the only template rule that is applied for namespace nodes.

The built-in template rules are treated as if they were imported implicitly before the stylesheet and so have lower import precedence than all other template rules. Thus, the author can override a built-in template rule by including an explicit template rule.

So, the reported behavior is the result of the application of the built-in templates -- the 1st and 2nd of all three of them.

It is a good XSLT design pattern to override the built-in templates with your own that will issue an error message whenever called so that the programmer immediately knows his transformation is "leaking":

For example, if there is this XML document:

<a>
  <b>
    <c>Don't want to see this</c>
  </b>
</a>

and it is processed with this transformation:

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

the result is:

<a name="a">
   <b name="b">Don't want to see this</b>
</a>

and the programmer will be greatly confused how the unwanted text appeared.

However, just adding this catch-all template helps avoid any such confusion and catch errors immediately:

 <xsl:template match="*">
  <xsl:message terminate="no">
   WARNING: Unmatched element: <xsl:value-of select="name()"/>
  </xsl:message>

  <xsl:apply-templates/>
 </xsl:template>

Now, besides the confusing output the programmer gets a warning that explains the problem immediately:

 WARNING: Unmatched element: c

Later Addition by Michael Kay for XSLT 3.0

In XSLT 3.0, rather than adding a catch-all template rule, you can specify the fallback behaviour on an xsl:mode declaration. For example, <xsl:mode on-no-match="shallow-skip"/> causes all nodes that are not matched (including text nodes) to be skipped, while <xsl:mode on-no-match="fail"/> treats a no-match as an error, and <xsl:mode warning-on-no-match="true"/> results in a warning.

这篇关于为什么 XSLT 默认输出所有文本?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆