Reputation: 15
I have 2 templates in XSL that I want to execute in a single XSL file. Original xml
<root>
<step1.alfa/>
<step1.bravo/>
<step1.charlie/>
<step1.delta/>
<step2.alfa/>
<step2.bravo/>
<step2.charlie/>
<step2.delta/>
This needs to be nested and then rename the element names.
But I can't figure out how to do those 2 templates in 1 single xslt. As the templates always start from the original xml.
First output
<root>
<step>
<step1.alfa/>
<step1.bravo/>
<step1.charlie/>
<step1.delta/>
</step>
<step>
<step2.alfa/>
<step2.bravo/>
<step2.charlie/>
<step2.delta/>
</step>
Second output
<root>
<step>
<alfa/>
<bravo/>
<charlie/>
<delta/>
</step>
<step>
<alfa/>
<bravo/>
<charlie/>
<delta/>
</step>
First template is to nest the steps and second is to rename them. I only show one, but I have a template for every element that needs to be renamed.
<xsl:template match="Values" name="recursive-steps">
<xsl:param name="var" select="2"/>
<xsl:choose>
<xsl:when test="$var > 0">
<STEP>
<xsl:for-each select="node()[starts-with(name(), concat('step', $var))]">
<xsl:copy-of select="."/>
</xsl:for-each>
</STEP>
<xsl:call-template name="recursive-steps">
<xsl:with-param name="var" select="$var - 1"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise/>
</xsl:choose>
</xsl:template>
<xsl:template match="*[substring(name(), string-length(name())-3) = 'alfa']">
<ALFA>
<xsl:apply-templates select="@*|node()" />
</ALFA>
</xsl:template>
Added the 2 templates here that I want to combine.
Upvotes: 0
Views: 1568
Reputation: 163262
In general the way you apply-templates to the result of a previous template is by capturing the result in a variable:
<xsl:variable name="temp">
<xsl:apply-templates select="x" mode="phase-1"/>
</xsl:variable>
<xsl:apply-templates select="$temp" mode="phase-2"/>
But because the variable is a result-tree-fragment, in XSLT 1.0 you have to use the exslt:node-set() extension to get around the restrictions on RTFs:
<xsl:apply-templates select="exslt:node-set($temp)" mode="phase-2"/>
Upvotes: 1
Reputation: 116959
Well, if you want the second template to be applied after the first, you should change this part:
<xsl:for-each select="node()[starts-with(name(), concat('step', $var))]">
<xsl:copy-of select="."/>
</xsl:for-each>
to:
<xsl:apply-templates select="node()[starts-with(name(), concat('step', $var))]"/>
or rather:
<xsl:apply-templates select="*[starts-with(name(), concat('step', $var, '.'))]"/>
However, your second template doesn't make much sense. I believe it should be something like:
<xsl:template match="*">
<xsl:element name="{substring-after(name(), '.')}"/>
</xsl:template>
Frankly, your first template is kinda awkward, too - I would suggest you look into Muenchian grouping for this task.
Upvotes: 0