davidpmccormick
davidpmccormick

Reputation: 308

Named template parameter as XPath for template match

Is it possible to specify a parameter of a named template as the match pattern in another template?

Here, if I try to call the 'excerpt' template and pass in an XPath as the 'path' param, I get an error:

<xsl:template name="excerpt">
    <xsl:param name="path" select="''" />
    <xsl:apply-templates select="$path" />
</xsl:template>

<xsl:template match="$path">
    <article class="newsarticle">
        <h2><a href="{$root}/news/view/{title/@handle}"><xsl:value-of select="title" /></a></h2>
        <xsl:copy-of select="excerpt/node()" />
    </article>
</xsl:template>

I can accomplish it with <xsl:for-each>, but I wondered if there was a good solution using something similar to the approach above.

Edit: here's what I'm trying to accomplish, working with a <xsl:for-each>:

<xsl:template name="excerpt">
    <xsl:param name="path" select="''" />
    <xsl:for-each select="$path">
        <article class="newsarticle">
            <h2><a href="{$root}/news/view/{title/@handle}"><xsl:value-of select="title" /></a></h2>
            <xsl:copy-of select="excerpt/node()" />
        </article>
    </xsl:for-each>
</xsl:template>

Edit: an example of calling the template:

<xsl:call-template name="excerpt">
    <xsl:with-param name="path" select="path/to/nodeset" />
</xsl:call-template>

Upvotes: 1

Views: 2400

Answers (2)

JLRishe
JLRishe

Reputation: 101748

Thanks for the additional information. One clarification to make here is that in that call-template there, you are passing a node-set, not a path. String values of paths are pretty much worthless in XSLT 1.0 without convoluted parsing logic or extension functions.

There is a way to do what you're trying to do, just in a slightly different way from what you envisioned. You just need to use a template with a generic match value and a mode value, like this.

<xsl:template name="excerpt">
    <xsl:param name="items" select="''" />
    <xsl:apply-templates select="$items" mode="excerptItem" />
</xsl:template>

<xsl:template match="node() | @*" mode="excerptItem">
    <article class="newsarticle">
        <h2>
          <a href="{$root}/news/view/{title/@handle}">
             <xsl:value-of select="title" />
          </a>
        </h2>
        <xsl:copy-of select="excerpt/node()" />
    </article>
</xsl:template>

But if the named template is only serving to invoke the match template, then you don't need the named template at all. You can just use the match template directly:

<xsl:apply-templates select="path/to/nodeset" mode="excerptItem" />

The purpose of the mode attribute is that when you specify mode in an apply-templates, the XSLT will only consider templates that also have that same mode value. So you could define two different templates that handled the same element in different ways:

<xsl:template match="Item" mode="header">
     Item in header: <xsl:value-of select="." />
</xsl:template>
<xsl:template match="Item" mode="body">
     Item in body: <xsl:value-of select="." />
</xsl:template>

Then you can specify which one you want to use at different times:

<div id="header">
    <xsl:apply-templates match="/root/Items/Item" mode="header" />
</div>
<div id="body">
    <xsl:apply-templates match="/root/Items/Item" mode="body" />
</div>

and the appropriate one would be used in each case. You can read more about modes here.

node() | @* is a generic XPath that matches any node or attribute, so if you use it in the match attribute of a template, you can make a template that will match almost anything you use in an apply-templates (as long as there isn't another template with higher precedence). Using that in combination with a mode allows you to make a template that you can invoke on any node and only at specific times when you want to. In your example, it looks like the element you will use with this template will always be the same, so it would probably be better practice to explicitly specify it:

<xsl:template match="ExportItem" mode="excerptItem">

Upvotes: 1

Dimitre Novatchev
Dimitre Novatchev

Reputation: 243579

Is it possible to get a parameter of a named template to act as the match path in another template?

No, in XSLT 2.0 the match pattern of a template can only contain a variable reference as an argument to an id() function.

See the XSLT 2.0 W3C Specificification for the complete grammar of a Pattern

http://www.w3.org/TR/xslt20/#pattern-syntax

In XSLT 1.0 it is an error to have a variable reference anywhere within a match pattern.

Upvotes: 0

Related Questions