XSLT3 未命名的 xsl:mode on-no-match 行为是不是应该应用于没有模式匹配但模式在应用模板上指定的元素?

Posted

技术标签:

【中文标题】XSLT3 未命名的 xsl:mode on-no-match 行为是不是应该应用于没有模式匹配但模式在应用模板上指定的元素?【英文标题】:Should an XSLT3 unnamed xsl:mode on-no-match behaviour be applied to an element that has no mode matched but a mode is specified on apply-templates?XSLT3 未命名的 xsl:mode on-no-match 行为是否应该应用于没有模式匹配但模式在应用模板上指定的元素? 【发布时间】:2020-05-01 04:45:23 【问题描述】:

这个问题更容易通过例子而不是文字来描述。

使用以下 XML

<?xml version="1.0" encoding="UTF-8"?>
<tests>
    <test>1</test>
    <test>2</test>
</tests>

如果我运行以下 XSLT3

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    expand-text="true"
    version="3.0">

    <xsl:output method="xml" />
    <xsl:mode on-no-match="shallow-copy" />
    <!--<xsl:mode name="test" on-no-match="shallow-copy"/>-->

    <xsl:template match="/">
        <mytests>
            <xsl:apply-templates/>
            <xsl:apply-templates mode="test"/>
        </mytests>
    </xsl:template>

    <xsl:template match="tests" mode="test">
        <modetest>
            <xsl:apply-templates mode="#current"/>
        </modetest>
    </xsl:template>
</xsl:stylesheet>

我在 Saxon 9 中得到以下输出

<?xml version="1.0" encoding="UTF-8"?>
<mytests>
    <tests>
        <test>1</test>
        <test>2</test>
    </tests>
    <modetest>
            1
            2
    </modetest>
</mytests>

您可以看到,当使用“测试”模式时,我们不会输出测试元素,只有该元素的内容。模式为“test”的元素“test”没有模板。

我猜想由于没有匹配,on-no-match="shallow-copy" 会从没有名称属性的 xsl:mode 中启动?我的猜测是,即使某个模式有效,一个没有命名的 xsl:mode 也将适用于所有没有匹配项(除非另一个 xsl:mode 定义的名称与当前模式匹配)。 如果您取消注释 xsl:mode name="test" on-no-match="shallow-copy" 那么一切都按预期工作(所以不需要解决方法,谢谢),但这意味着在应用了很多很多模式的 XSLT -templates,我需要定义很多很多命名的 xsl:modes 只是为了获得身份模板行为。

谁能指出我做错了什么或者这是否符合 w3C 规范?

【问题讨论】:

【参考方案1】:

“我的猜测是没有命名的 xsl:mode 将适用于所有没有匹配,即使模式是有效的”

对不起,你的猜测是错误的。可以这样想:有一个名为#unnamed 的模式,任何xsl:templatexsl:apply-templatesxsl:mode 元素没有@mode 属性默认为mode="#unnamed"。 (这是一个近似值,当指定default-mode 时会变得更复杂,但这是基本概念。)

无法“批量”定义大量模式的属性,每个模式需要一个 xsl:mode 声明。

【讨论】:

感谢您的澄清,但很遗憾。【参考方案2】:

任何模式的默认内置处理是text-only-copy,请参阅https://www.w3.org/TR/xslt-30/#modes“如果使用模式名称(例如在 xsl:template 声明或 xsl:apply-templates 指令中)并且没有声明该模式出现在样式表中,该模式使用默认属性隐式声明”和https://www.w3.org/TR/xslt-30/#built-in-rule

有六组可用的内置模板规则。那套 被选择是由选择的模式的属性 xsl:apply-templates 指令。该属性是使用 xsl:mode 声明的on-no-match 属性,它采用以下之一 六个值deep-copyshallow-copydeep-skipshallow-skiptext-only-copy,或fail,默认为text-only-copy

XSLT 2 或 1 中的内置默认处理没有什么不同。

如果必须用单独的xsl:mode声明单独声明身份转换显得过于繁琐,当然你也可以写一个模板

<xsl:template match="@* | node()" mode="#all">
   <xsl:copy>
      <xsl:apply-templates select="@*" mode="#current"/>
      <xsl:apply-templates mode="#current"/>
   </xsl:copy>
</xsl:template>

https://www.w3.org/TR/xslt-30/#using-modes

【讨论】:

谢谢马丁。明白了。我过去曾使用过这样的“所有模式”身份转换,我只是试图停止使用 XSLT3 特性来做这件事。在我的特定用例中,我有很多模式。 据我了解,几种模式没有声明性的单一xsl:mode。让我们等一下 Michael Kay 会说什么(如果 Saxonica 不太忙于 Saxon-JS 2 :))。

以上是关于XSLT3 未命名的 xsl:mode on-no-match 行为是不是应该应用于没有模式匹配但模式在应用模板上指定的元素?的主要内容,如果未能解决你的问题,请参考以下文章

xslt 转换错误:XTSE0010:元素 xsl:mode 不得直接出现在 xsl:stylesheet 中

SaxonJS - xslt3 - ObjectNotFound: (xslt3:String) [], CommandNotFoundException

如何停止 xslt3.0 的 xml-to-json() 函数将数字转换为指数表示法

Marklogic xml 转换中的 XSLT 3.0 支持

XSLT 3.0 - 无法在 XSLT 3.0 xml-to-json() 中获取对象数组

XSLT 3.0 - 在 XSLT 3.0 xml-to-json() 中出现错误“重复键值”