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

Xslt 使用.Net转换类时未将参数传递到模板中,xslt,Xslt,我正在使用.Net XslCompiledTranform运行一些简单的XSLT(参见下面的简化示例) 示例XSLT仅用于显示传递到模板的参数值。输出是我期望的(即 瓦卢亚 当我使用Saxon 9.0时,但当我在.net中使用XslCompiledTransform(XslTransform)时,我得到 <result xmlns:p1="http://www.doesnotexist.com"> <valueOfParamA></valueOfParamA

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

示例XSLT仅用于显示传递到模板的参数值。输出是我期望的(即


瓦卢亚
当我使用Saxon 9.0时,但当我在.net中使用XslCompiledTransform(XslTransform)时,我得到

<result xmlns:p1="http://www.doesnotexist.com">
  <valueOfParamA></valueOfParamA>
</result>

问题是,当我使用.Net类时,paramA的参数值没有传递到模板中。我完全不明白为什么。当我在Visual Studio中逐步执行时,调试器说将使用paramA='valueA'调用模板,但当执行切换到模板时,paramA的值为空

有人能解释为什么会发生这种情况吗?这是MS实现中的一个bug还是(更有可能)我正在做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>

经过多次试验后,我发现修改模板可以应用于

 <xsl:apply-templates select="$nodeset/*" mode="AParticularMode">
        <xsl:with-param name="paramA" select="'valueA'"/>
 </xsl:apply-templates>

(注意,
select=“$nodeset/*”
而不是
select=“nodeset”
)使它在.Net和Saxon中按我所希望的那样工作


不过,如果有人能解释我第一次尝试失败的原因,我将不胜感激。

回答您的问题

为什么我的第一次尝试失败了

当您在代码中舒适地使用node-set()时,我想您可能很清楚结果树片段

通过利用RTF[Result tree fragment],您可以将“foo”视为一个节点

变量$nodeset存储了节点的树结构,因此您可以将其值视为节点集,其中as变量$nodeset仍然是一个变量。如果您要应用模板,然后应用于,则其子节点[精确地说是元素]显示为其值

而不是你可以用

<xsl:apply-templates select="$nodeset/p1:foo" mode="AParticularMode">

更准确地说,

没有什么奇怪的——这是任何符合XSLT1.0的处理器的预期行为

说明
$nodeset
变量定义为:

XSLT1.0中包含一个完整的xml文档——一个文档节点,在XPath1.0中由
/
表示

所以,

<xsl:apply-templates select="$nodeset" mode="AParticularMode">
  <xsl:with-param name="paramA" select="'valueA'"/>
</xsl:apply-templates>
根据规范: “每个模式还有一个内置的模板规则,允许在样式表中没有显式模板规则成功匹配模式的情况下,在相同模式下继续递归处理。此模板规则同时适用于元素节点和根节点。下面显示了m的内置模板规则的等效项颂歌m

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

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

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


我可以看到您对节点集函数返回值的看法。我假设$nodeset看起来像$nodeset,但实际上是这样,但在我看来仍然有两个WTF:-a)ifI可以看到您对节点集函数返回值的看法。我假设$nodeset的值是p1:foo元素,但它不是-它是一个以p1:foo为子元素的节点。但是,在我看来仍然存在WTF:-如果$nodeset确实是一个以p1:foo为子元素的节点,为什么
select=“$nodeset”“
将其匹配为p1:foo(因为调用了我的模板)。或者换一种说法,为什么
apply templates select=“$nodeset”
apply templates select=“$nodeset/*”
都调用我的模板-我本以为只有1个调用模板,而不是两个都调用。是的,非常困惑/复杂的问题:-P,甚至我都想知道背后的技术原因。。我们会让这个问题“热”2-3天;-)你很接近事实,但并不完全正确:)请看我的答案中的解释。这是一个好问题(+1),也是新手和经验丰富的专业人士最常犯的错误之一:)请看我的答案以了解详细信息。谢谢迪米特的解释。我是XSLT的新手,不知道每个模式都有一个内置的模板(每次我想了解XSLT时,我都会发现我的知识中有另一个漏洞)。我假设XSLT 2.0中的情况有所不同,这就是为什么我在Saxon 9.0中得到不同的结果。@ChrisF,是的,我更新了我的答案,解释了XSLT 2.0的行为。我非常肯定,你知道答案。。很高兴见到你:-)
<xsl:apply-templates select="$nodeset" mode="AParticularMode">
  <xsl:with-param name="paramA" select="'valueA'"/>
</xsl:apply-templates>
<xsl:template match="*|/">
  <xsl:apply-templates/>
</xsl:template>
<xsl:template match="*|/" mode="m">
  <xsl:apply-templates mode="m"/>
</xsl:template>
<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>