XSLT: selecting nodes matching either of 2 criteria

A

Andy Fish

hello,

I am trying to determine whether the preceding sibling (ignoring anything
other than nodes or comments) is a comment. in procedural terms it's:

for each preceding sibling
if (node type is node or comment)
return (node type = comment)
end if
end loop

the first step seems to be to list the preceding siblings which are either
nodes or comments, but this doesn't work:

<xsl: if test="preceding-sibling:*|comment()">

because the | has too high a priority, and I can't use brackets like this:

<xsl: if test="preceding-sibling:(*|comment())">

because they aren't allowed. any clues here please.

TIA

Andy
 
P

Pavel Lepin

Andy Fish said:
I am trying to determine whether the preceding sibling
(ignoring anything other than nodes or comments) is a
comment.

the first step seems to be to list the preceding siblings
which are either nodes or comments, but this doesn't work:

<xsl: if test="preceding-sibling:*|comment()">

Are you sure you need an if? Anyway, first of all, : is a
namespace resolution operator, not an axis resolution
operator. Secondly,

preceding-sibling::*|preceding-sibling::comment()

is a bit closer to being correct than your attempt.
because the | has too high a priority, and I can't use
brackets like this:

<xsl: if test="preceding-sibling:(*|comment())">

Be wary when fooling around with (). It's weird in some
ways. I'd use:

*
[
preceding-sibling::node()
[self::* or self::comment()][1][self::comment()]
]

Note that 1 instead of last(). preceding-sibling:: axis
causes the resulting nodeset to use the reverse document
order.
 
R

Richard Tobin

Andy Fish said:
I am trying to determine whether the preceding sibling (ignoring anything
other than nodes or comments) is a comment. in procedural terms it's:

"Other than nodes"? Everything's a node. Did you mean "other than elements"
(as the "*" later suggests)?
for each preceding sibling
if (node type is node or comment)
return (node type = comment)
end if
end loop

Again, do you really mean "node type is node"? Surely "node type is
element"?
the first step seems to be to list the preceding siblings which are either
nodes or comments, but this doesn't work:

<xsl:if test="preceding-sibling:*|comment()">

because the | has too high a priority, and I can't use brackets like this:

<xsl:if test="preceding-sibling:(*|comment())">

Apart from the priority, this is testing the wrong thing. You can
correct the priority by changing it to

preceding-sibling::*|preceding-sibling::comment()

but that tests whether the node *has* a preceding sibling that's an
element or comment.

My guess is that you want to know, of the preceding siblings that are elements
or comments, whether the nearest one is a comment. If so, then you might
try

(preceding-sibling::*|preceding-sibling::comment())[1][self::comment()] *WRONG*

but that won't work, because though "[1]" means first in the backwards direction
for preceding-sibling, it doesn't mean that for a parenthesized expression - it
means first in document order. In fact you want

(preceding-sibling::*|preceding-sibling::comment())[last()][self::comment()]
or
preceding-sibling::node()[self::*|self::comment()][1][self::comment()]

-- Richard
 
A

Andy Fish

Thanks Richard (yes of course I meant elements not nodes - d'oh!)

anyway that did the trick.

Pavel's solution was similar but I think he fell foul of the problem with
[1] and [last()]

it's quite tricky to get ones head round though :)

Richard Tobin said:
Andy Fish said:
I am trying to determine whether the preceding sibling (ignoring anything
other than nodes or comments) is a comment. in procedural terms it's:

"Other than nodes"? Everything's a node. Did you mean "other than
elements"
(as the "*" later suggests)?
for each preceding sibling
if (node type is node or comment)
return (node type = comment)
end if
end loop

Again, do you really mean "node type is node"? Surely "node type is
element"?
the first step seems to be to list the preceding siblings which are either
nodes or comments, but this doesn't work:

<xsl:if test="preceding-sibling:*|comment()">

because the | has too high a priority, and I can't use brackets like this:

<xsl:if test="preceding-sibling:(*|comment())">

Apart from the priority, this is testing the wrong thing. You can
correct the priority by changing it to

preceding-sibling::*|preceding-sibling::comment()

but that tests whether the node *has* a preceding sibling that's an
element or comment.

My guess is that you want to know, of the preceding siblings that are
elements
or comments, whether the nearest one is a comment. If so, then you might
try

(preceding-sibling::*|preceding-sibling::comment())[1][self::comment()]
*WRONG*

but that won't work, because though "[1]" means first in the backwards
direction
for preceding-sibling, it doesn't mean that for a parenthesized
expression - it
means first in document order. In fact you want


(preceding-sibling::*|preceding-sibling::comment())[last()][self::comment()]
or
preceding-sibling::node()[self::*|self::comment()][1][self::comment()]

-- Richard
 
P

Pavel Lepin

Andy Fish said:
Pavel's solution was similar but I think he fell foul of
the problem with [1] and [last()]

Nope, I didn't. You should pay attention. If you just tried
stuffing that XPath expression in your xsl:if and it didn't
work, that's because it's meant for XSLT-idiomatic
select/match processing.
 
A

Andy Fish

Ah - understood thanks

I must admit I find these subtleties somewhat difficult to get to grips
with.

I have great respect for the simplicity of XSLT and I'm sure everything is
there for a reson, but for the casual user the difference in semantics
depending on where you use an expression are often confusing

Pavel Lepin said:
Andy Fish said:
Pavel's solution was similar but I think he fell foul of
the problem with [1] and [last()]

Nope, I didn't. You should pay attention. If you just tried
stuffing that XPath expression in your xsl:if and it didn't
work, that's because it's meant for XSLT-idiomatic
select/match processing.
 

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,999
Messages
2,570,246
Members
46,840
Latest member
BrendanG78

Latest Threads

Top