Re: AW: [xsl] Selection of every second node

Subject: Re: AW: [xsl] Selection of every second node
From: Jeni Tennison <mail@xxxxxxxxxxxxxxxx>
Date: Tue, 21 Aug 2001 14:56:43 +0100
Hi Conny,

> <xsl:template match="another">
>   <li>
>     <xsl:if test="boolean(parent::node()[(position() mod 2) = 0])">
>       <xsl:attribute name="type">disc</xsl:attribute>
>     </xsl:if>
>     <xsl:value-of select="." />
>   </li>
> </xsl:template>

When you use the position() function in a predicate, you're testing
the position of each of the nodes that are selected by the step
amongst the other nodes in the step. In:

  parent::node()[(position() mod 2) = 0]

you're selecting the parent node of the another element. There can
only be one parent node of any element, so the node set gathered by
the step only has one node in it. Then filtering this node set (which
only contains one node) to get only those whose position mod 2 is
equal to 0. There are no such nodes in the node set, so the location
path returns an empty node set, and the test evaluates as false
(there's no need to use boolean() there, by the way - the contents of
a test attribute are automatically converted to boolean values).

You want to test the position of the current node's parent node
amongst its siblings. There are a couple of ways you could do that.

First, you could use a location path to collect the preceding siblings
of the another element's parent node:

  parent::node()/preceding-sibling::node

(or ../preceding-sibling::node)

Count the number of nodes that gives you - if it's odd then the node
element is an even node, otherwise it's odd:

  <xsl:if test="(count(../preceding-sibling::node) mod 2) = 1">
    <xsl:attribute name="type">disc</xsl:attribute>
  </xsl:if>

Or just:

  <xsl:if test="count(../preceding-sibling::node) mod 2">
    <xsl:attribute name="type">disc</xsl:attribute>
  </xsl:if>

A second approach is to apply templates to the parent node element in
'typeAttribute' mode:

  <xsl:apply-templates select=".." mode="typeAttribute" />

and then have two templates in typeAttribute mode that match nodes in
different positions. One to match odd node elements, which does
nothing:

<xsl:template match="node[(position() mod 2) = 1]"
              mode="typeAttribute" />

and another to match even node elements, which adds the attribute:

<xsl:template match="node[(position() mod 2) = 0]"
              mode="typeAttribute">
  <xsl:attribute name="type">disc</xsl:attribute>
</xsl:template>

If you test the position of a node in a match pattern, its position is
assessed within the set of its similar siblings.

I hope that helps,

Jeni

---
Jeni Tennison
http://www.jenitennison.com/


 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Current Thread