Wokoman
Wokoman

Reputation: 1129

How to mimic calling template-match with a parameter value?

I'm looking for a workaround on passing parameters to a template-match. I'm aware this isn't allowed within XPath, and therefore I'm looking for a 'plan B' solution.

This is what I wished would work :

Part 1 of xslt (2.0) :

<xsl:template match="/">
    <xsl:for-each select="//Main/PageList/Page">
    <xsl:result-document href="{@ID}.xml">
        <Page ID="{@ID}">
            <xsl:apply-templates select="node()">
                <xsl:with-param name="theID" select="@ID"/>
            </xsl:apply-templates>
        </Page>
    </xsl:result-document>
    </xsl:for-each> 
</xsl:template>

So fairly straightforward, don't bother about the tags used, what it does in essence is go through a node, and for each node it creates a single XML file. Each node starts with an ID, and it's this ID I'd like to make available for other templates. Unfortunately this works fine for named templates, but it doesn't work for matched ones (if I understood the theory correctly at least)

So below is what I'd like to see working :

<!-- identity template -->
    <xsl:template match="node()|@*">
    <xsl:param name="theID"/>
    <xsl:copy>
        <xsl:apply-templates select="node()|@*">
            <xsl:with-param name="theID" select="$theID"/>
        </xsl:apply-templates>
    </xsl:copy>
</xsl:template>

<!-- lots of templates here doing what I want them to do -->

<!-- one template creating an issue -->

<xsl:template match="@src">
<!-- would be nice to know the current ID, but unfortunately this one stays empty... -->
<xsl:param name="theID"/>

<!-- clean current attribute a bit -->
<xsl:variable name="S1" select="replace(.,'\.\.\/','')"/>

<xsl:attribute name="src">
<xsl:choose>
<xsl:when test="contains($S1,'common')">
<!-- just use current value, don't bother about current ID -->
    <xsl:value-of select="$S1"/>
</xsl:when>
<xsl:otherwise>
    <!-- use ID parameter -->
    <xsl:value-of select="concat($theID,'_',$S1)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
</xsl:template>

Don't look at the code as such, it's just a smaller part of the whole file, but the essence is that I want to use the ID parameter from my first part (match="/") inside the other template (match="@src"), but this seems to be rather complex.

Am I missing something ? If I'm just having bad luck and it's not possible indeed, would anyone have an advice how I could proceed ?

Thanks in advance !

Upvotes: 1

Views: 2410

Answers (2)

Dimitre Novatchev
Dimitre Novatchev

Reputation: 243569

Your problem is here:

<xsl:apply-templates select="node()">
  <xsl:with-param name="theID" select="@ID"/>
</xsl:apply-templates>

the select attribute specifies that the processing should continue on any children nodes of the current node.

However node() only selects children nodes (elements, text nodes, processing instructions and comments) -- not attributes.

Solution:

  1. In order to directly cause processing of (all) attributes of the current node, use:

--

<xsl:apply-templates select="@*">
  <xsl:with-param name="theID" select="@ID"/>
</xsl:apply-templates>

.2. In order to cause the processing only of the src attribute of the current node use:

--

<xsl:apply-templates select="@src">
  <xsl:with-param name="theID" select="@ID"/>
</xsl:apply-templates>

.3. In order to process indirectly attributes tof the descendants of the current node, do:

--

<xsl:apply-templates select="node()|@*">
  <xsl:with-param name="theID" select="@ID"/>
</xsl:apply-templates>

You also must ensure that any template that processes node() must have an xsl:param named theID and that it must pass this param in any xsl:apply-templates instruction.

In practice this means that you mus override all XSLT built-in templates, because they aren't aware of your xsl:param.

Upvotes: 1

Martin Honnen
Martin Honnen

Reputation: 167716

I think instead of

        <xsl:apply-templates select="node()">
            <xsl:with-param name="theID" select="@ID"/>
        </xsl:apply-templates>

you rather want

        <xsl:apply-templates select="node()">
            <xsl:with-param name="theID" select="parent::Page/@ID"/>
        </xsl:apply-templates>

assuming you want to pass on the ID attribute of the parent Page element.

On the other hand the select="node()" select any child nodes like child elements, child comment nodes, child text nodes, child processing instruction nodes, so I don't see why you later show a template matching an attribute node.

Upvotes: 0

Related Questions