Surender Thakran
Surender Thakran

Reputation: 4054

XSLT: How to write an `<xsl:apply-templates/>` for matching nodes with templates with modes and without modes without disturbing the order?

Suppose I have the following XML:

<root>
    <a>1</a>
    <b>2</b>
    <a>3</a>
    <c>4</c>
    <a>5</a>
    <a>6</a>
    <b>7</b>
    <a>8</a>
    <c>9</c>
</root>

Consider the following XSL:

<xsl:template match="root">
    <xsl:apply-templates select="a | b | c"/>    <!-- matches node 'b' with a non-mode template instead of the one with mode="test" -->
</xsl:template>

<xsl:template match="a">
    <xsl:value-of select="."/>
</xsl:template>

<xsl:template match="b">
    <xsl:text> ignore </xsl:text>
</xsl:template>

<xsl:template match="b" mode="test">
    <xsl:value-of select="."/>
</xsl:template>

<xsl:template match="c">
    <xsl:value-of select="."/>
</xsl:template>

I am trying to write a XSL template call which will match all the nodes inside the root node with its corresponding template but the node b should be matched with a template with mode="test". The order of the node handling should not be disturbed.

The desired output is:

1
2
3
4
5
6
7
8
9

Upvotes: 0

Views: 196

Answers (2)

Michael Kay
Michael Kay

Reputation: 163458

I would define a new mode, and then redirect it as appropriate:

<xsl:template match="root">
    <xsl:apply-templates select="a | b | c" mode="new"/>  
</xsl:template>

<xsl:template match="a|c" mode="new">
    <xsl:apply-templates select="."/>
</xsl:template>

<xsl:template match="b" mode="new">
    <xsl:apply-templates select="." mode="test"/>
</xsl:template>

Another solution is to define template rules that apply in more than one mode, so the "unnamed mode" templates for a and c would also apply to mode "new", while the mode="test" template for b would also apply to mode "new". IIRC this requires XSLT 2.0 (you don't say which version you are using - please do so in future).

Upvotes: 1

Joel M. Lamsen
Joel M. Lamsen

Reputation: 7173

I do not know if this will be applicable to you. Instead of

<xsl:template match="root">
    <xsl:apply-templates select="a | b | c"/>
</xsl:template>

do

<xsl:template match="root">
    <xsl:for-each select="*">
        <xsl:choose>
            <xsl:when test="name()='a'">
                <xsl:apply-templates select="."/>
            </xsl:when>
            <xsl:when test="name()='b'">
                <xsl:apply-templates select="." mode="test"/>
            </xsl:when>
            <xsl:when test="name()='c'">
                <xsl:apply-templates select="."/>
            </xsl:when>
        </xsl:choose>
    </xsl:for-each>
</xsl:template>

Upvotes: 2

Related Questions