带模式的XSLT apply-template - 没有匹配模式的结果不正确

时间:2010-08-26 17:13:36

标签: xslt mode

这是一个简单的案例。

这是我的XML:

<?xml version="1.0" encoding="utf-8" ?>
<dogs>
    <dog type="Labrador">
        <Name>Doggy</Name>
    </dog>
    <dog type="Batard">
        <Name>Unknown</Name>
    </dog>
</dogs>

此XML与两个Xslt一起使用。这是常见的:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
    <xsl:output method="text"/>

    <xsl:template match="dogs">
        <xsl:text>First template&#13;&#10;</xsl:text>
        <xsl:apply-templates select="." mode="othertemplate" />
    </xsl:template>
</xsl:stylesheet>

这是孩子:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
    <xsl:include href="transform.xslt"/>

    <xsl:template match="dogs" mode="othertemplate">
        <xsl:text>&#9;&#9;Other template</xsl:text>
    </xsl:template>
</xsl:stylesheet>

孩子包括普通孩子(称为transform.xslt)。

当我执行孩子时,我得到了预期的结果:

First template
        Other template

当我执行常用的时,我得到了这个奇怪的结果:

First template


        Doggy


        Unknown

常见的模板应用模式“othertemplate”。此模式仅在子xslt中包含。

我想要的是,如果没有模板“othertemplate”,那么就不应输出任何内容。

我不想为所有不必使用此模板模式的xslt文件包含模式为“othertemplate”的模板和空体...

我该怎么办?

由于

2 个答案:

答案 0 :(得分:10)

XSLT中的内置模板规则

由于XSLT的内置模板规则(也称为默认模板),因此会显示元素内容和额外的空白。当没有其他匹配模板时,将应用这些规则。

是内置模板规则
<xsl:template match="*|/">
  <xsl:apply-templates/>
</xsl:template>

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

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

内置模板规则递归处理根节点和元素节点并复制文本(如果选择了属性节点,则复制文本属性值)。用于处理指令和注释的内置模板规则是什么都不做。默认情况下不处理命名空间节点。请注意,<xsl:apply-templates/>实际上是<xsl:apply-templates select="child::node()"/>的简写,因此它不会选择属性或命名空间节点。

每种模式还有一个内置模板规则。这些模板类似于元素和root的默认模板,除非它们以相同的模式继续处理。

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

由于您的样式表没有与模式dogs匹配的othertemplate模板,因此会应用此内置模板规则,在这种情况下会导致处理所有子节点并最终打印文本节点。源文档元素之间的缩进和换行也是文本节点,因此它们也会被打印并在输出中产生额外的空白。

由于<xsl:apply-templates select="."/>

而对非终止循环发出警告

通常apply-templates用于处理后代。在您的示例代码中,您在调用apply-templates时选择了当前节点。如果由于其中有apply-templates命令而应用模板本身,则可能导致非终止循环。以下示例

<xsl:template match="foobar">
  <!-- This is an infinite loop -->
  <xsl:apply-templates select="."/>
</xsl:template>
顺便说一下。关于组合样式表的一般规则,请仔细考虑应运行哪个模板以及应导入或包含哪个模板。 (我有read作为一般惯例,Michael Kay似乎建议使用<xsl:import>将一般情况样式表导入特殊情况样式表,而不是反过来。)

答案 1 :(得分:6)

每种模式定义并选择

The built-in XSLT templates 。因此,选择了文本节点的内置模板,并且(根据定义)它输出文本节点。

要取消此操作,您需要使用空模板覆盖所需模式中的文本节点的内置模板(也可能用于元素):

<xsl:template match="text()" mode="othertemplate"/>

在导入的样式表中包含上述内容。