xsl recursive loop node by index
I have created a recursive template for getting the first n number of items from my XML.
It uses an index(counter) just like how I would in a for loop. Now how can I get a node from my XML using the index?
I have tried [position()=$index] but it had weird behaviour when trying to get deeper nodes in the XML hierarchy.
If I have XML such as:
<0>
<1>
<2>ite开发者_运维知识库m</2>
<2>item</2>
<2>item</2>
<2>item</2>
<2>item</2>
<2>item</2>
</1>
</0>
I want to be able to count through and copy the 2's until I have as many as I want.
You say you want to process your elements in groups of n. The following XSLT 1.0 solution does it:
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
<xsl:param name="pGroupCount" select="3" />
<xsl:template match="/lvl-0">
<xsl:copy>
<!-- select the nodes that start a group -->
<xsl:apply-templates mode="group" select="
lvl-1/lvl-2[position() mod $pGroupCount = 1]
" />
</xsl:copy>
</xsl:template>
<xsl:template match="lvl-2" mode="group">
<!-- select the nodes belong to the current group -->
<xsl:variable name="current-group" select="
. | following-sibling::lvl-2[position() < $pGroupCount]
" />
<!-- output the current group, you can also do calculations with it -->
<group id="{position()}">
<xsl:copy-of select="$current-group" />
</group>
</xsl:template>
</xsl:stylesheet>
When applied to this input document:
<lvl-0>
<lvl-1>
<lvl-2>item.0</lvl-2>
<lvl-2>item.1</lvl-2>
<lvl-2>item.2</lvl-2>
<lvl-2>item.3</lvl-2>
<lvl-2>item.4</lvl-2>
<lvl-2>item.5</lvl-2>
<a>foo</a><!-- to prove that position() calculations still work -->
<lvl-2>item.6</lvl-2>
<lvl-2>item.7</lvl-2>
<lvl-2>item.8</lvl-2>
<lvl-2>item.9</lvl-2>
</lvl-1>
</lvl-0>
The following output is generated:
<lvl-0>
<group id="1">
<lvl-2>item.0</lvl-2>
<lvl-2>item.1</lvl-2>
<lvl-2>item.2</lvl-2>
</group>
<group id="2">
<lvl-2>item.3</lvl-2>
<lvl-2>item.4</lvl-2>
<lvl-2>item.5</lvl-2>
</group>
<group id="3">
<lvl-2>item.6</lvl-2>
<lvl-2>item.7</lvl-2>
<lvl-2>item.8</lvl-2>
</group>
<group id="4">
<lvl-2>item.9</lvl-2>
</group>
</lvl-0>
To understand this you must know how position()
works. When used like this:
lvl-1/lvl-2[position() mod $pGroupCount = 1]
it refers to the position of lvl-2
nodes within their respective (!) parent. In this case, there is only one parent, so item.0
has position 1 and item.9
has position 10.
When used like this:
following-sibling::lvl-2[position() < $pGroupCount]
it refers to the relative position along the following-sibling::
axis. In this context, item.1
would have a relative position of 1 in regard to item.0
. (Basically, this is the same as the above, which just counts along the (implicit) child::
axis.)
When used on its own, like here:
<group id="{position()}">
it refers to the position of the current node in the batch that is being processed at the moment. In our case the "batch" consists of nodes that start a group (item.0
, item.3
, item.6
, item.9
), so it goes from 1 to 4.
I would use <xsl:for-each ... > along with position() instead of recursion.
I don't quite see why you need a recursive template to do this. You could use an <xsl:for-each> to achieve this. (I changed the element name to make it legal) For example:
<xsl:variable name='n' select='10'/>
<xsl:for-each select='two[position() < $n]'>
<!-- do whatever you need to do -->
</xsl:for-each>
You can use an select attribute you want and you could include an <xsl:sort> in the for-each if your input is more complex than your example.
精彩评论