Re: [xsl] inconsistent Preceding-Sibling behaviour when nested in For-Each

Subject: Re: [xsl] inconsistent Preceding-Sibling behaviour when nested in For-Each
From: Alan Stein <as2@xxxxxxxxxxx>
Date: Sat, 02 Nov 2002 17:26:55 -0500
Hi Jeni,

Thanks much for your clear explanation. The inclusion of a positional predicate, [1], made the code behave much more desirably. A few combined issues (multiple node evaluations with a single conditional statement, node ordering inside/outside a step) led to confusing behavior but you've straightened things out.

Regards,
  --Alan


At 09:31 AM 11/2/2002 +0000, you wrote:
Hi Alan,

> I've observed a reproducible XSL behaviour that I just can't
> understand. "preceding-sibling", "following-sibling", and
> conditional expressions based on these axes appear to behave oddly
> when placed in a "for-each" element.
>
>   My observations of the unusual behavior within the "for-each" loop:
>
> -- "following-sibling" behaves exactly as I would expect
> -- "preceding sibling" unexpectedly always refers to the first sibling in
> the document

When you collect together a node set and use it to do something in
XSLT, for example if you iterate over it using <xsl:for-each> or take
the value of the first node with <xsl:value-of>, then XSLT *always*
gives you the node set in document order.

When you collect together all the preceding-siblings of a node, and
handle them in document order the first of those nodes is the first of
the siblings -- the first child of the parent -- not the closest of
those siblings.

If you want to get the *closest* of the siblings then you can use
[last()] as follows:

<xsl:value-of select="(preceding-sibling::person/name)[last()]" />

Or you can use [1] *in the step when you select the preceding
sibling*:

<xsl:value-of select="preceding-sibling::person[1]/name" />

In a step, the order used to evaluate positional predicates such as
[1] is based on the axis used in the step. In a forward axis, such as
following-sibling, it's the same as document order. In a reverse axis,
such as preceding-sibling, it's reverse document order. Basically, if
you use [1] you always end up with the node that's closest to the node
that you're on.

To summarise: Node sets are always treated as if they were in document
order. Within a step, the order of the nodes depends on the axis
that's used in the step.

> -- "if" statements behave erraticly: neither comparisons of current
> nodes to "preceding-sibling" nor comparisons to "following-sibling"
> appear to work completely.

When you make comparisons that involve node sets in XSLT, the
comparison actually tests whether any combination of tests between
individual nodes and the value would be true. For example, if you do:

<xsl:if test="name = preceding-sibling::person/name">...</xsl:if>

you're actually testing whether the name of this person is the same as
the name of *any* preceding sibling's name. Again, if you want to just
test the *immediately* preceding sibling's name, then you should use a
positional predicate in the step where you select the preceding
sibling, so that you only select the first rather than all of them:

<xsl:if test="name = preceding-sibling::person[1]/name">...</xsl:if>

Cheers,

Jeni

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


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


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


Current Thread