Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using XSLT Apply-Templates to conditionally select nodes

Tags:

xml

xslt

xpath

Let's say I have an xml document like this:

<director>
    <play>
        <t>Nutcracker</t>
        <a>Tom Cruise</a>
    </play>
    <play>
        <t>Nutcracker</t>
        <a>Robin Williams</a>
    </play>
    <play>
        <t>Grinch Stole Christmas</t>
        <a>Will Smith</a>
    </play>
    <play>
        <t>Grinch Stole Christmas</t>
        <a>Mel Gibson</a>
    </play>
</director>

Now I want to be able to select all the plays with Will Smith as an actor and reformat it into something like this:

<Plays>
    <Play title="Grinch Stole Christmas">
       <star>Will Smith</star>
       <star>Mel Gibson</star>
    </Play>
</Plays>

I only want to use apply-templates.. No xsl:if or for each loops (I have contrived this example as a simpler version of what I'm doing so you can help me understand how to use xpath within a match statement)

Here is what I have so far:

<?xml version="1.0"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" />
        <xsl:template match="/director">
                <Plays>
                <xsl:apply-templates select="play"/>
                </Plays>
        </xsl:template>

        <xsl:template match="play[a='Will Smith']">
                <play title="{data(t)[1]}">
                <xsl:apply-templates select="a"/>
                </play>
        </xsl:template>

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

Basically I am just unsure of how to filter out nodes using XPath in the match attribute of the template. Any help would be great!

like image 923
Msencenb Avatar asked Oct 20 '10 21:10

Msencenb


People also ask

What does xsl apply-templates select * mean?

The <xsl:apply-templates> element first selects a set of nodes using the expression specified in the select attribute. If this attribute is left unspecified, all children of the current node are selected.

What is the difference between call template and apply template in XSLT?

With <xsl:apply-templates> the current node moves on with every iteration, whereas <xsl:call-template> does not change the current node.

How do you call a template in XSLT?

You can name a template by using the name attribute of the xsl:template element. Further, the name called by the mandatory name attribute of the xsl:call-template element must match the name specified by the name attribute of the xsl:template element.

How do xsl templates work?

The <xsl:apply-templates> element applies a template to the current element or to the current element's child nodes. If we add a "select" attribute to the <xsl:apply-templates> element, it will process only the child elements that matches the value of the attribute.


1 Answers

The condition should be on xsl:apply-templates instead of xsl:template:

<Plays>
  <xsl:apply-templates select="play[a='Will Smith']">"/>
</Plays>

In your solution, you are transforming ALL <play> nodes. For play nodes that match the condition, your template is applied. But for those that don't match the condition, a default template ("identity transform") is applied instead.

Alternatively, you could keep the condition on xsl:template match, but add another template for <play> that do not match the condition, to transform those <play> into nothing:

    <xsl:template match="play[a='Will Smith']">
      <play title="{data(t)[1]}">
        <xsl:apply-templates select="a"/>
      </play>
    </xsl:template>

    <xsl:template match="play">
    </xsl:template>
like image 61
ckarras Avatar answered Sep 22 '22 05:09

ckarras