使用.Net转换类时,参数未传递到模板中

Chr*_*ell 5 xslt

我使用.Net XslCompiledTranform来运行一些简单的XSLT(参见下面的简化示例).

示例XSLT旨在简单地显示传递给模板的参数的值.输出是我所期望的(即

<result xmlns:p1="http://www.doesnotexist.com">
  <valueOfParamA>valueA</valueOfParamA>
</result>
Run Code Online (Sandbox Code Playgroud)

当我使用Saxon 9.0时,但是当我在.net中使用XslCompiledTransform(XslTransform)时,我得到了

<result xmlns:p1="http://www.doesnotexist.com">
  <valueOfParamA></valueOfParamA>
</result>
Run Code Online (Sandbox Code Playgroud)

问题是当我使用.Net类时,paramA的参数值没有传递到模板中.我完全难以理解为什么.当我在Visual Studio中单步调试时,调试器表示将使用paramA ='valueA'调用模板,但是当执行切换到模板时,paramA的值为空.

任何人都可以解释为什么会这样吗?这是MS实现中的错误还是(更有可能)我在做XSLT禁止的事情?

任何帮助非常感谢.

这是我正在使用的XSLT

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:extfn="http://exslt.org/common"  exclude-result-prefixes="extfn" xmlns:p1="http://www.doesnotexist.com">
<!-- 
    Replace msxml with
    xmlns:extfn="http://exslt.org/common" 
    xmlns:extfn="urn:schemas-microsoft-com:xslt" 
 -->
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
    <xsl:variable name="resultTreeFragment">
        <p1:foo>
        </p1:foo>
    </xsl:variable>
    <xsl:variable name="nodeset" select="extfn:node-set($resultTreeFragment)"/>
    <result>
        <xsl:apply-templates select="$nodeset" mode="AParticularMode">
            <xsl:with-param name="paramA" select="'valueA'"/>
        </xsl:apply-templates>
    </result>
</xsl:template>

<xsl:template match="p1:foo" mode="AParticularMode">
    <xsl:param name="paramA"/>

    <valueOfParamA>
        <xsl:value-of select="$paramA"/>
    </valueOfParamA>
</xsl:template>
</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)

Dim*_*hev 4

没有什么奇怪的——这是任何 XSLT 1.0 兼容处理器的预期行为。

说明:该$nodeset变量定义为:

<xsl:variable name="nodeset" select="extfn:node-set($resultTreeFragment)"/>

XSLT 1.0 中包含一个完整的xml 文档——文档节点,在 XPath 1.0 中用 表示/

所以,

<xsl:apply-templates select="$nodeset" mode="AParticularMode">
  <xsl:with-param name="paramA" select="'valueA'"/>
</xsl:apply-templates>
Run Code Online (Sandbox Code Playgroud)

/如果存在这样的模板,将在指定模式下应用与树(文档节点)匹配的模板。在您的情况下,不存在这样的模板。因此,应用了内置的 XSLT 1.0 模板/(属于每种模式)。

内置模板的文本可以在规范中找到

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

当然,内置模板对您的参数一无所知$paramA,也不会将其传递给应用的模板。

因此,最后,您的模板匹配p1:foo"mode="AParticularMode"被选择进行处理。没有任何内容作为参数的值传递,因此它没有值——因此<xsl:value-of>不会产生甚至单个字符或节点。

要解决此问题,只需添加一个模板匹配/and in mode "AParticularMode"

<xsl:template match="/" mode="AParticularMode">
  <xsl:param name="paramA"/>

  <xsl:apply-templates mode="AParticularMode">
    <xsl:with-param name="paramA" select="$paramA"/>
  </xsl:apply-templates>
</xsl:template>
Run Code Online (Sandbox Code Playgroud)

现在你得到了想要的结果。

在 XSLT 2.0 (Saxon 9) 中,您会观察到不同的行为,因为 XSLT 2.0 中的内置模板根据定义会重新传输应用它们的所有参数 - 请参阅XSLT 2.0 规范

“如果使用参数调用内置规则,这些参数将在隐式 xsl:apply-templates 指令中传递。”

  • 谢谢 Dimitre 非常清晰的解释。我是 XSLT 的菜鸟,并且不知道每种模式都有一个内置模板(每次我认为我正在了解 XSLT 时,我都会发现我的知识中存在另一个漏洞)。我认为 XSLT 2.0 中的情况有所不同,这就是为什么我在 Saxon 9.0 中得到不同结果的原因。 (2认同)