Pieter_mov
Pieter_mov

Reputation: 15

XSLT 1.0 apply template on result of another template

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

Answers (2)

Michael Kay
Michael Kay

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

michael.hor257k
michael.hor257k

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

Related Questions