Reputation: 1129
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
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:
--
<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
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