XSL 命名参数“with-param”使用“应用模板”;

发布于 2024-10-03 02:07:45 字数 2402 浏览 3 评论 0原文

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

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

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

XML 文件:

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

main.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>

test.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-templatesxsl:with-param,但是选择这个 具体由 name= 内的值 实际的模板,以便它可以 明确地用于单个 模板并被所有其他人忽略 (即使我想添加其他, 不同的名称,参数为 其他模板稍后)?

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

  3. 有更好的方法来完成这个任务吗?

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

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

My questions are at the bottom of this post, if you wish to read them before the full explanation.

I'm converting an XML document to a pretty web page using XSL, and am having trouble with correctly passing a variable. I have many xsl:templates defined, and need to pass a specific parameter to just one of them. I was hoping that I would be able to pass a named parameter that would presumably be sent to all of the xsl:templates, but only be used by a single one and ignored by the others. However, when trying to test this for myself (and my limited understanding of XSL), I was unable to pass the parameter at all, let alone test if it was accidentally disturbing any other xsl:templates.

The following is simplified example code (typed up for this question, it may contain a typo or two). I have many many different xsl:templates defined to deal with nodes in the XML, and everything has been working fine until now. It is in adding a parameter to these templates that I appear to be having issues.

XML file:

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

main.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>

test.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>

Output (actual):

TEST1 TEST2

Output (expected/desired):

TEST1 TEST_PARAMETER TEST2

My questions in regards to this:

  1. Is it possible to send a named
    parameter to all of my
    xsl:templates using an
    xsl:apply-templates with
    xsl:with-param, but select this
    value specifically by name= within
    the actual template so that it can
    be explicitly used in a single
    template and ignored by all others
    (even if I wanted to add other,
    differently named, parameters for
    other templates later)?

  2. What am I doing wrong with my current sample code that it does not seem to receive the parameter at all?

  3. Is there a better way to accomplish this?

Edit: I want to make it clear that due to other output within the test.xsl:testNode template, I know for sure that it IS being successfully called. It is ONLY the parameter part that is not working. I do not mean to waste people's time figuring out why that template is not being called. It is.

Update: In response to the answers I initially received, which pointed out that the example I made up was not completely correct (my mistake) and did not very clearly show the issue (ie: that the correct template is being called, but that only the parameter appears to not be working), I have replaced the examples with much better ones. This example more clearly shows that the testNode template is successfully being called, but that the parameter does not seem to be passed. I have tested this numerous times, before and after consideration of the previous answers to this question. I am absolutely stumped, as everything appears to be correct from what I have read elsewhere and what people have suggested so far.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

怀里藏娇 2024-10-10 02:07:45

我对此的疑问:

  1. 是否可以将命名参数发送到我的所有 xsl:templates
    使用 xsl:apply-templates 与
    xsl:with-param,但是选择这个值
    具体按名称=在
    实际模板,以便它可以
    在单个模板中明确使用
    并被所有其他人忽视(即使我
    想添加其他不同的
    其他模板的命名、参数
    稍后)?

。在 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提供了更准确的信息,证明了我的猜测。

现在很明显,问题是由于允许 XSLT 内置 -在模板中为wrapperNode选择元素节点。当然,这个模板不知道任何参数,它不使用 testParam 参数,也不传递该参数。因此,内置模板中的 会导致选择与 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>

My questions in regards to this:

  1. Is it possible to send a named parameter to all of my xsl:templates
    using an xsl:apply-templates with
    xsl:with-param, but select this value
    specifically by name= within the
    actual template so that it can be
    explicitly used in a single template
    and ignored by all others (even if I
    wanted to add other, differently
    named, parameters for other templates
    later)?

Yes. In XSLT 2.0 one may use the so called "tunnel parameters", but in XSLT 1.0 this is the way to have some parameters reach some remote template down the chain.

Another way is to have global parameters, so that they wouldn't have to be passed through every template in the chain.

.2. What am I doing wrong with my current sample code that it does not
seem to receive the parameter at all?

The reason is in the code you haven't shown to us. Or maybe the source XML document you have in your real case isn't the same as the one provided here. I ran the provided code and I couldn't repro the problem at all -- the desired output is produced.

My guess is that some other template is selected before the template that matches testNode. This template doesn't know anything about the passed parameter and it doesn't pass it to the templates that it, on its turn, applies. Thus the parameter is not passed at all to the template matching testNode.

My guess is that if you replace:

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

with

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

you could get the desired output.

Also, you could trace with an XSLT debugger (such as the one in Visual Studio) and see exactly which template is selected.

.3. Is there a better way to accomplish this?

As I said earlier, global parameters can be used as alternative -- I am not sure that this is better, though.

Finally, here is the code that I ran that cannot repro your problem:

XSLT stylesheet:

<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 document:

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

Result:

  This is text1
  TEST_PARAMETER
  This is text2

UPDATE:

The OP has provided more accurate information which prooves my guess.

Now it is obvious that the problem is caused by allowing the XSLT built-in template for element node to be selected for wrapperNode. This template, naturally, doesn't know about any parameters and it doesn't use the testParam parameter nor does it pass this parameter through. Thus, the <xsl:apply-templates/> in the built-in template causes the template matching testNode to be selected without passing any parameter to it. THis explains the reported behavior/result.

Solution: The solution is to specify a template matching wrapperNode that accepts a parameter named testParam and passes it through when it applies templates:

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

Now when this transformation is applied on the provided XML document, the expected result is produced:

<html>
<body>
  TEST1
  TEST_PARAMETER
  TEST2
 </body>
</html>
演出会有结束 2024-10-10 02:07:45

元素不能出现在 XSL 样式表中的位置。当我删除它们和结束标签并在 Oxygen/XML 中运行它时,我得到了您“所需的”输出。我认为您想将这些标签放在顶级模板中,在这种情况下,它将在 htmlbody 标签内生成输出。

您使用了哪种 XSLT 处理器并且没有抱怨无效的样式表?

Your <html> and <body> elements can't occur where they are in an XSL stylesheet. When I remove them and the closing tags and run this in Oxygen/XML I get your "desired" output. I think you want to put those tags INSIDE the top-level template, in which case it would generate the output within html and body tags.

Which XSLT processor did you use that didn't complain about the invalid stylesheet?

终止放荡 2024-10-10 02:07:45

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

<html><body>

  TEST1
  TEST_PARAMETER
  TEST2

</body></html>

I ran the poster's 3 samples above as is and got this result using Notepad++ 7.7.1 on Wine under Ubuntu 18.04 with the XML Tools installed.

<html><body>

  TEST1
  TEST_PARAMETER
  TEST2

</body></html>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文