Oleg Vazhnev
Oleg Vazhnev

Reputation: 24057

xsl: how to use parameter inside "match"?

My xsl has a parameter

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

I want to use it inside match

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

But this doesn't work. I guess a can not use parameters inside ''. How to fix/workaround that?

Upvotes: 6

Views: 12330

Answers (4)

Flynn1179
Flynn1179

Reputation: 12075

Well, you could use a conditional instruction inside the template:

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

You just need to be aware that this template will handle all elements that satisfy the first condition. If you have a different template that handles elements that match the first, but not the second, then use an <xsl:choose>, and put the other template's body in the <xsl:otherwise> block.

Or, XSLT2 can handle it as is if you can switch to an XSLT2 processor.

Upvotes: 6

Glenn N
Glenn N

Reputation: 845

This topic had the answer to my question, but the proposed solution by Flynn1179 was not quite correct for me (YMMV). So try it the way it is suggested by people more expert than me, but if it doesn't work for you, consider how I solved it. I am using xsltproc that only handles XSL version 1.0.

I needed to match <leadTime hour="0024">, but use a param: <xsl:param name="hour">0024</xsl:param>. I found that: <xsl:if test="@hour='{$hour}'"> did not work, despite statements here and elsewhere that this is the required syntax for XSL v.1.0. Instead, the simpler <xsl:if test="@hour=$hour"> did the job.

One other point: it is suggested above by Dimitre that you put template inside if statement. xsltproc complained about this: instead I put the if statement inside the template:

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

Upvotes: 2

Michael Kay
Michael Kay

Reputation: 163262

In XSLT 2.0 you can refer to global variables within a match pattern, but the syntax is simpler than your guess:

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

rather than

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

Also, the semantics are not what you appear to be expecting: a variable referenced on the lhs of "/" must contain a node-set, not a fragment of an XPath expression.

Upvotes: 1

Dimitre Novatchev
Dimitre Novatchev

Reputation: 243459

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

"It is an error for the value of the match attribute to contain a VariableReference"

There is no such limitation in XSLT 2.0, so use XSLT 2.0.

If due to unsurmountable reasons using XSLT2.0 isn't possible, put the complete body of the <xsl:template> instruction inside an <xsl:if> where the test in conjunction with the match pattern is equivalent to the XSLT 2.0 match pattern that contains the variable/parameter reference(s).

In a more complicated case where you have more than one template matching the same kind of node but with different predicates that reference variables/parameters, then a wrapping <xsl:choose> will need to be used instead of a wrapping <xsl:if>.

Upvotes: 8

Related Questions