18

我的问题在这篇文章的底部,如果你想在完整解释之前阅读它们。

我正在使用 XSL 将 XML 文档转换为漂亮的网页,并且无法正确传递变量。我xsl:template定义了许多 s,并且需要将特定参数传递给其中一个。我希望我能够传递一个命名参数,该参数可能会被发送到所有的xsl:templates,但只能被一个人使用而被其他人忽略。然而,当我试图为自己测试这个(以及我对 XSL 的有限理解)时,我根本无法传递参数,更不用说测试它是否意外地干扰了任何其他xsl:templates。

以下是简化的示例代码(为此问题键入,可能包含一两个错字)。我定义了许多不同xsl:template的 s 来处理 XML 中的节点,并且到目前为止一切正常。正是在向这些模板添加参数时,我似乎遇到了问题。

XML 文件:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="main.xsl"?>
<wrapperNode>
  <testNode>
    <subNode/>
  </testNode>
</wrapperNode>

主要的.xsl:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:import href="test.xsl"/>
<xsl:output method="html" indent="yes"/>

<xsl:template match="/">

<html>
  <body>
      <xsl:apply-templates>
        <xsl:with-param name="testParam">TEST_PARAMETER</xsl:with-param>
      </xsl:apply-templates>
  </body>
</html>

</xsl:template>
</xsl:stylesheet>

测试.xsl:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="testNode">
  <xsl:param name="testParam" />
  TEST1
  <xsl:value-of select="$testParam" />
  TEST2
</xsl:template>
</xsl:stylesheet>

输出(实际):

TEST1 TEST2

输出(预期/期望):

TEST1 TEST_PARAMETER TEST2

我对此的问题:

  1. xsl:template是否可以使用 xsl:apply-templateswith 向我的所有 s 发送一个命名参数 xsl:with-param,但在实际模板中专门选择此值,name=以便它可以在单个模板中显式使用并被所有其他人忽略(即使我想添加其他模板的其他名称不同的参数)?

  2. 我当前的示例代码做错了什么,它似乎根本没有收到参数?

  3. 有没有更好的方法来实现这一点?

编辑:我想明确指出,由于test.xsl:testNode模板中的其他输出,我确定它被成功调用。只有参数部分不起作用我并不是要浪费人们的时间来弄清楚为什么没有调用该模板。这是。

更新:针对我最初收到的答案,指出我编写的示例并不完全正确(我的错误)并且没有很清楚地显示问题(即:正在调用正确的模板该参数似乎不起作用),我已将示例替换为更好的示例。这个例子更清楚地表明testNode模板被成功调用,但参数似乎没有被传递。在考虑这个问题的先前答案之前和之后,我已经测试了很多次。我完全被难住了,因为从我在别处读到的内容和人们迄今为止的建议来看,一切似乎都是正确的。

4

3 回答 3

33

我对此的问题:

  1. 是否可以使用带有 xsl:with-param 的 xsl:apply-templates 向我的所有 xsl:templates 发送命名参数,但在实际模板中通过 name= 专门选择此值,以便可以在单个模板并被所有其他模板忽略(即使我想稍后为其他模板添加其他名称不同的参数)?

的。在 XSLT 2.0 中可能会使用所谓的“隧道参数”,但在 XSLT 1.0 中,这是让一些参数到达链下的某个远程模板的方法。

另一种方法是使用全局参数,这样就不必通过链中的每个模板传递它们。

.2. 我当前的示例代码做错了什么,它似乎根本没有收到参数?

原因在于您没有向我们展示的代码。或者,您在真实案例中拥有的源 XML 文档可能与此处提供的不同。我运行了提供的代码,但我根本无法重现问题——产生了所需的输出。

我的猜测是在匹配的模板之前选择了其他一些模板testNode该模板对传递的参数一无所知,并且不会将其传递给它轮流应用的模板。因此,参数根本没有传递给模板匹配testNode

我的猜测是,如果你更换:

  <xsl:apply-templates> 
    <xsl:with-param name="testParam">TEST_PARAMETER</xsl:with-param> 
  </xsl:apply-templates> 

  <xsl:apply-templates select="testNode"> 
    <xsl:with-param name="testParam">TEST_PARAMETER</xsl:with-param> 
  </xsl:apply-templates> 

您可以获得所需的输出。

此外,您可以使用 XSLT 调试器(例如 Visual Studio 中的调试器)进行跟踪,并准确查看选择了哪个模板。

.3. 有没有更好的方法来实现这一点?

正如我之前所说,可以使用全局参数作为替代方案——不过我不确定这是否更好。

最后,这是我运行的无法重现您的问题的代码:

XSLT 样式表

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>

 <xsl:template match="/">
      This is text1
      <xsl:apply-templates>
        <xsl:with-param name="testParam">TEST_PARAMETER</xsl:with-param>
      </xsl:apply-templates>
      This is text2
 </xsl:template>

 <xsl:template match="testNode">
  <xsl:param name="testParam" />
  <xsl:value-of select="$testParam" />
 </xsl:template>
</xsl:stylesheet>

XML 文档

<?xml-stylesheet type="text/xsl" href="main.xsl"?>
<testNode>
  <subNode/>
</testNode>

结果

  This is text1
  TEST_PARAMETER
  This is text2

更新:

OP提供了更准确的信息,这证明了我的猜测。

现在很明显,问题是由于允许wrapperNode. 这个模板自然不知道任何参数,它不使用testParam参数,也不传递这个参数。因此,<xsl:apply-templates/>内置模板中的 导致选择模板匹配testNode而不向其传递任何参数。这解释了报告的行为/结果。

解决方案:解决方案是指定一个模板匹配wrapperNode,该模板匹配接受一个名为的参数testParam,并在应用模板时将其传递:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="html" indent="yes"/>

 <xsl:template match="/">
  <html>
    <body>
        <xsl:apply-templates>
          <xsl:with-param name="testParam" select="'TEST_PARAMETER'"/>
        </xsl:apply-templates>
    </body>
  </html>
 </xsl:template>

 <xsl:template match="testNode">
  <xsl:param name="testParam" />
  TEST1
  <xsl:value-of select="$testParam" />
  TEST2
 </xsl:template>

 <xsl:template match="wrapperNode">
  <xsl:param name="testParam" />

  <xsl:apply-templates>
   <xsl:with-param name="testParam" select="$testParam"/>
  </xsl:apply-templates>
 </xsl:template>
</xsl:stylesheet>

现在,当将此转换应用于提供的 XML 文档时,会产生预期的结果

<html>
<body>
  TEST1
  TEST_PARAMETER
  TEST2
 </body>
</html>
于 2010-11-18T23:11:20.830 回答
1

您的<html>and<body>标记不能出现在 XSL 样式表中的位置。当我删除它们和结束标签并在 Oxygen/XML 中运行它时,我会得到你的“期望”输出。我认为您想将这些标签放在顶级模板中,在这种情况下,它将在htmlbody标签中生成输出。

您使用的哪个 XSLT 引擎不会抱怨样式表无效?

于 2010-11-18T22:06:19.437 回答
0

我按原样运行海报的 3 个示例,并在安装了 XML 工具的 Ubuntu 18.04 下的 Wine 上使用 Notepad++ 7.7.1 得到了这个结果。

<html><body>

  TEST1
  TEST_PARAMETER
  TEST2

</body></html>
于 2019-07-12T20:43:18.790 回答