Use apply-templates selectively in XSLT

A

abhishek.smu

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
 
R

roy axenov

<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>
said:
(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>
said:

<xsl:template match="node"/>
<xsl:template
match="node[count(following-sibling::node) &lt; 3]">
<xsl:copy><xsl:apply-templates/></xsl:copy>
said:
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.
 
A

abhishek.smu

<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>
(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 match="node"/>
<xsl:template
match="node[count(following-sibling::node) &lt; 3]">
<xsl:copy><xsl:apply-templates/></xsl:copy>
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.

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top