By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
460,022 Members | 1,379 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 460,022 IT Pros & Developers. It's quick & easy.

Use apply-templates selectively in XSLT

P: n/a
Given an XML like:

<root>
<node>8</node>
<node>21</node>
<node>-7</node>
<node>13</node>
<node>43</node>
<node>2</node>
</root>
how might I select only the 2nd, 3rd and 4th nodes (or more
generically, any selective set of nodes like first 4, last 3, every
other node etc)? Note that since my XSLT obviously won't know the
value inside a node, I can't just pick a node with the values of 21,
-7 and 13 using xsl:if or something like it. I tried playing around
with some things like for-each and creating a template with some sort
of a recursive scenario, but to no avail.
Any help is appreciated.
Thanks
Abhishek

Feb 23 '07 #1
Share this Question
Share on Google+
3 Replies


P: n/a
ab**********@gmail.com wrote:
how might I select only the 2nd, 3rd and 4th nodes
Write a select expression that tests position().

--
Joe Kesselman / Beware the fury of a patient man. -- John Dryden
Feb 23 '07 #2

P: n/a
On Feb 23, 7:51 pm, "abhishek....@gmail.com"
<abhishek....@gmail.comwrote:
<root>
<node>8</node>
<node>21</node>
<node>-7</node>
<node>13</node>
<node>43</node>
<node>2</node>
</root>

how might I select only the 2nd, 3rd and 4th nodes
<xsl:template match="node"/>
<xsl:template
match="node[position() &gt; 1 and position() &lt; 5]">
<xsl:copy><xsl:apply-templates/></xsl:copy>
</xsl:template>
(or more generically, any selective set of nodes like
first 4,
<xsl:template match="node"/>
<xsl:template
match="node[count(preceding-sibling::node) &lt; 4]">
<xsl:copy><xsl:apply-templates/></xsl:copy>
</xsl:template>
last 3,
<xsl:template match="node"/>
<xsl:template
match="node[count(following-sibling::node) &lt; 3]">
<xsl:copy><xsl:apply-templates/></xsl:copy>
</xsl:template>
every other node
<xsl:template match="node"/>
<xsl:template
match="node[position() mod 2=0]">
<xsl:copy><xsl:apply-templates/></xsl:copy>
</xsl:template>

Note that depending on what exactly you are trying to do,
it might be a good idea to use xsl:key/key() combo together
with selecting the nodesets you need instead of
template-based matching of the nodes you need processed.
Note that since my XSLT obviously won't know the value
inside a node
I beg your pardon? Of course it will. Use string() or just
'.'. Note that this is a bit esoteric and often not a very
good practice if you stop and think about it for a moment.
Anyway, processing based on a value of the node is
definitely possible.
I can't just pick a node with the values of 21, -7 and 13
Of course you can.

<xsl:template match="node"/>
<xsl:template
match="node[.=21 or .=-7 or .=13]">
<xsl:copy><xsl:apply-templates/></xsl:copy>
</xsl:template>

Or did you mean that your problem requires matching of
nodes based on their position in the document, not on the
plain data they contain? If that is the case, the solutions
are described above.

Another thing to keep in mind is that if you're processing
a homogeneous nodeset using node position to switch
processing modes, it is often an indicator of poor XML
design of your source document; but whatever suits you.
using xsl:if or something like it. I tried playing around
with some things like for-each
As a rule of the thumb, if and choose should be replaced
with predicate-based selection and matching where possible.
Where impossible, go ahead and use if or choose, but
remember that it's a good idea to feel somewhat dirty and
uncomfortable afterwards.

You should also realize that for-each is very different
from what you would expect out of similarly based language
constructs or library methods in imperative languages such
as Perl, PHP, C++ or Java. Use template-based processing
instead.
and creating a template with some sort of a recursive
scenario, but to no avail.
I'm not sure I can see how recursive processing would be
helpful in this particular case.

--
roy axenov

Feb 23 '07 #3

P: n/a
On Feb 23, 2:03 pm, "roy axenov" <r_axe...@mail.ruwrote:
On Feb 23, 7:51 pm, "abhishek....@gmail.com"

<abhishek....@gmail.comwrote:
<root>
<node>8</node>
<node>21</node>
<node>-7</node>
<node>13</node>
<node>43</node>
<node>2</node>
</root>
how might I select only the 2nd, 3rd and 4th nodes

<xsl:template match="node"/>
<xsl:template
match="node[position() &gt; 1 and position() &lt; 5]">
<xsl:copy><xsl:apply-templates/></xsl:copy>
</xsl:template>
(or more generically, any selective set of nodes like
first 4,

<xsl:template match="node"/>
<xsl:template
match="node[count(preceding-sibling::node) &lt; 4]">
<xsl:copy><xsl:apply-templates/></xsl:copy>
</xsl:template>
last 3,

<xsl:template match="node"/>
<xsl:template
match="node[count(following-sibling::node) &lt; 3]">
<xsl:copy><xsl:apply-templates/></xsl:copy>
</xsl:template>
every other node

<xsl:template match="node"/>
<xsl:template
match="node[position() mod 2=0]">
<xsl:copy><xsl:apply-templates/></xsl:copy>
</xsl:template>

Note that depending on what exactly you are trying to do,
it might be a good idea to use xsl:key/key() combo together
with selecting the nodesets you need instead of
template-based matching of the nodes you need processed.
Note that since my XSLT obviously won't know the value
inside a node

I beg your pardon? Of course it will. Use string() or just
'.'. Note that this is a bit esoteric and often not a very
good practice if you stop and think about it for a moment.
Anyway, processing based on a value of the node is
definitely possible.
I can't just pick a node with the values of 21, -7 and 13

Of course you can.

<xsl:template match="node"/>
<xsl:template
match="node[.=21 or .=-7 or .=13]">
<xsl:copy><xsl:apply-templates/></xsl:copy>
</xsl:template>

Or did you mean that your problem requires matching of
nodes based on their position in the document, not on the
plain data they contain? If that is the case, the solutions
are described above.

Another thing to keep in mind is that if you're processing
a homogeneous nodeset using node position to switch
processing modes, it is often an indicator of poor XML
design of your source document; but whatever suits you.
using xsl:if or something like it. I tried playing around
with some things like for-each

As a rule of the thumb, if and choose should be replaced
with predicate-based selection and matching where possible.
Where impossible, go ahead and use if or choose, but
remember that it's a good idea to feel somewhat dirty and
uncomfortable afterwards.

You should also realize that for-each is very different
from what you would expect out of similarly based language
constructs or library methods in imperative languages such
as Perl, PHP, C++ or Java. Use template-based processing
instead.
and creating a template with some sort of a recursive
scenario, but to no avail.

I'm not sure I can see how recursive processing would be
helpful in this particular case.

--
roy axenov
WOW !!!

Thank you so much. Since I am a beginner at this, I had never even
heard of the node and position things. This is absolute magic to me.

And yes, I did mean that my "problem requires matching of nodes based
on their position in the document, not on the plain data they
contain."

Once again, thanks a lot.

Abhishek

Feb 24 '07 #4

This discussion thread is closed

Replies have been disabled for this discussion.