【问题标题】:xsl: how to use parameter inside "match"?xsl:如何在“匹配”中使用参数?
【发布时间】:2013-08-29 06:45:51
【问题描述】:

我的xsl有一个参数

<xsl:param name="halfPath" select="'halfPath'"/>

我想在比赛中使用它

<xsl:template match="Element[@at1='value1' and not(@at2='{$halfPath}/another/half/of/the/path')]"/>

但这不起作用。我猜一个不能在''里面使用参数。如何解决/解决这个问题?

【问题讨论】:

    标签: xslt


    【解决方案1】:

    XSLT 1.0 W3C Specification forbids referencing variables/parameters inside a match pattern

    "这是一个错误的值 匹配属性以包含一个 变量引用”

    XSLT 2.0 中没有这样的限制,所以请使用 XSLT 2.0

    如果由于无法克服的原因无法使用 XSLT2.0,请将 &lt;xsl:template&gt; 指令的完整主体放在 &lt;xsl:if&gt; 中,其中与匹配模式结合的测试等同于 XSLT 2.0 匹配模式包含变量/参数引用。

    在更复杂的情况下,如果您有多个模板匹配相同类型的节点,但具有引用变量/参数的不同谓词,则需要使用包装 &lt;xsl:choose&gt; 而不是包装 &lt;xsl:if&gt;

    【讨论】:

    • 很抱歉这个凌乱的评论。我会删除它。与此同时,我在question 中准备了一个干净的示例
    【解决方案2】:

    嗯,你可以在模板中使用条件指令:

    <xsl:template match="Element[@at1='value1']">
      <xsl:if test="not(@at2=concat($halfPath,'/another/half/of/the/path'))">
        .. do something
      </xsl:if>
    </xsl:template>
    

    您只需要注意此模板将处理满足第一个条件的所有元素。如果您有一个不同的模板来处理与第一个匹配但不匹配第二个的元素,则使用&lt;xsl:choose&gt;,并将另一个模板的主体放在&lt;xsl:otherwise&gt; 块中。

    或者,XSLT2 可以按原样处理它,就像您可以切换到 XSLT2 处理器一样。

    【讨论】:

    • 我也必须在我的参数上使用 string(),由于某种原因没有它就无法工作... string($halfPath)
    • 您可以在模板中使用条件,但上面显示的代码不正确。 test 表达式不是属性值模板,因此 {} 不会导致替换。相反,您正在测试@at2 是否等于文字字符串{$halfPath}/...,这不是您想要的。有关更多详细信息,请参阅@MichaelKay 的答案。
    • @LarsH:好点子-我从问题中逐字复制了条件,我没有注意到它无论如何都是无效的。现在修好了。
    • 观察:当使用标识模板复制非常大的 XML 文件以仅修改整个文件中出现的极少数属性实例时,使用至少一个 XSLT 1.0 处理器,使用 xsl:if或模板内的 xsl:choose 比使用匹配表达式慢几个数量级(使用硬编码文字来解决无法在匹配表达式中使用变量/参数的问题)。重点?无法在匹配表达式中使用变量的代价可能会严重影响 XSLT 2.0 升级困难是否值得忍受以实现目标。
    【解决方案3】:

    这个话题回答了我的问题,但 Flynn1179 提出的解决方案对我来说并不完全正确(YMMV)。因此,请按照比我更专业的人建议的方式尝试它,但如果它对您不起作用,请考虑我是如何解决的。我正在使用仅处理 XSL 1.0 版的 xsltproc。

    我需要匹配 &lt;leadTime hour="0024"&gt;,但使用参数:&lt;xsl:param name="hour"&gt;0024&lt;/xsl:param&gt;。我找到: &lt;xsl:if test="@hour='{$hour}'"&gt; 不起作用,尽管此处和其他地方声明这是 XSL v.1.0 所需的语法。 相反,更简单的 &lt;xsl:if test="@hour=$hour"&gt; 完成了这项工作。

    还有一点:Dimitre 建议您将模板放在 if 语句中。 xsltproc 对此抱怨:相反,我将 if 语句放在模板中:

    <xsl:template match="leadTime">
      <xsl:if test="@hour=$leadhour">
        <xsl:copy>
          <xsl:apply-templates select="node() | @*"/>
        </xsl:copy>
      </xsl:if>
    </xsl:template>
    

    【讨论】:

    • +1 表示注意到接受的答案的代码是错误的,并给出了一个可行的解决方案。顺便说一句,Dimitre 并不是建议您将模板放在 if 语句中;他说要把模板的body(内容)放在if 语句中。
    【解决方案4】:

    在 XSLT 2.0 中,您可以在匹配模式中引用全局变量,但语法比您猜测的要简单:

    <xsl:template match="Element[@at1='value1' and 
                  not(@at2=$halfPath/another/half/of/the/path)]"/>
    

    而不是

    <xsl:template match="Element[@at1='value1' and 
                  not(@at2='{$halfPath}/another/half/of/the/path')]"/>
    

    此外,语义不是您所期望的:在“/”的 lhs 上引用的变量必须包含节点集,而不是 XPath 表达式的片段。

    【讨论】:

      猜你喜欢
      • 2011-03-08
      • 2021-10-26
      • 1970-01-01
      • 1970-01-01
      • 2011-10-16
      • 1970-01-01
      • 1970-01-01
      • 2012-02-07
      • 1970-01-01
      相关资源
      最近更新 更多