Reputation: 628
Sorry but a total xslt noob here
Given XML that looks like:
<Foo>
<Bar />
<Baz />
<Qax />
<FooBar />
</Foo>
Is there an XSLT that will limit the number of child nodes under Foo so that there are only 3?
Upvotes: 1
Views: 2102
Reputation: 12075
There are three ways of doing this:
Firstly, you can instruct the template that handles the Foo
element to only process the first three child nodes:
<xsl:template match="Foo">
<xsl:copy> <!-- can substitute with 'Foo' in this instance -->
<xsl:apply-templates select="*[position() <= 3]" />
</xsl:copy>
</xsl:template>
Or, if the first three child nodes don't need any individual treatment, you can use a template like this to handle the children:
<xsl:template match="Foo/*[position() <= 3]">
<!-- process the child element here -->
</xsl:template>
The two downsides to this approach are that the remaining children of Foo
can be processed by other templates, for example if you had one for specifically handling FooBar
nodes, and also there's no easy way of treating your Bar
and Baz
elements differently.
The third method is to use an empty template that is applied to all child nodes of Foo
after the third one like this:
<xsl:template match="Foo/*[position() > 3]" />
This method also gives you the advantage of being able to apply individual templates for Bar
and Baz
if you need to.
Upvotes: 0
Reputation: 243479
This transformation uses and overrides the identity rule/template:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*" name="identity">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*/*[position() > 3]"/>
</xsl:stylesheet>
When applied on the provided XML document:
<Foo>
<Bar />
<Baz />
<Qax />
<FooBar />
</Foo>
the wanted, correct result is produced:
<Foo>
<Bar/>
<Baz/>
<Qax/>
</Foo>
Explanation:
The identity rule/template copies every node "as-is".
We have just one additional template that overrides the identity rule for any element that is a child of the top element with position greater than 3. This template dos nothing (has an empty body), which effectively prevents any such element from being copied to the output (or as we use to say, "deletes" it).
Do note:
Using and overriding the identity rule is the most fundamental and powerful XSLT design pattern.
Using this design pattern is recommended over a simple <xsl:copy-of>
, because it allows the nodes not only to be copied, but to be processed by any template we provide. Attributes of all elements are also processed.
Upvotes: 2
Reputation: 24826
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/Foo">
<xsl:copy>
<xsl:copy-of select="*[position()<4]"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
gets:
<Foo>
<Bar/>
<Baz/>
<Qax/>
</Foo>
Upvotes: 0