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!
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.
With <xsl:apply-templates> the current node moves on with every iteration, whereas <xsl:call-template> does not change the current node.
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.
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.
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>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With