views:

1585

answers:

3

given this simplified data format:

<a>
    <b>
        <c>C1</c>
        <d>D1</d>
        <e>E1</e>
        <f>don't select this one</f>
    </b>
    <b>
        <c>C2</c>
        <d>D2</d>
        <e>E1</e>
        <g>don't select me</g>
    </b>
    <c>not this one</c>
    <d>nor this one</d>
    <e>definitely not this one</e>
</a>

How would you select all the Cs, Ds and Es that are children of B elements?

Basically, something like:

a/b/(c|d|e)

In my own situation, instead of just "a/b/", the query leading up to selecting those C,D,E nodes is actually quite complex so I'd like to avoid doing this:

a/b/c|a/b/d|a/b/e

...if that's possible?

+5  A: 

You can avoid the repetition with an attribute test instead:

a/b/*[local-name()='c' or local-name()='d' or local-name()='e']

Contrary to Dimitre's antagonistic opinion, the above is not incorrect in a vacuum where the OP has not specified the interaction with namespaces. The self:: axis is namespace restrictive, local-name() is not. If the OP's intention is to capture c|d|e regardless of namespace (which I'd suggest is even a likely scenario given the OR nature of the problem) then it is "another answer that still has some positive votes" which is incorrect.

You can't be definitive without definition, though I'm quite happy to delete my answer as genuinely incorrect if the OP clarifies his question such that I am incorrect.

annakata
Calling the facts "antagonistic opinion" is something deplorable. If you are not sure whether your answer is correct or not, then why in the first place should you submit such an answer?
Dimitre Novatchev
Doesn't the fact which answer is accepted demonstrate with absolute clarity which answer the OP considers correct?
Dimitre Novatchev
My *very clearly made* point is that neither you nor I can be definitive, and that your downvote is misplaced since my answer is not outright wrong. The fact the OP accepts an answer is irrelevant, since he cannot accept both, both will work for most cases, and mine was deleted at the time.
annakata
Further, I am saying that I contest your so called "facts", and it is *my* opinion that you are being transparently antagonistic. What purpose do your comments "still has positive votes" and "I explain why the one that is most voted at the moment is incorrect" serve?
annakata
Both these comments you are asking about serve the truth: to clearly show what is correct and what is incorrect -- and in this case it can be exactly determined. As for "offensive", please use a dictionary. There is nothing offensive in revealing the truth. The reverse is really offensive.
Dimitre Novatchev
No, no it cannot be exactly determined - I've repeatedly said now: both could be correct, both are functional on a simple document, it entirely depends on what the OP wants from namespacing. You seem wilfully ignorant of this, perhaps because it could put you in the wrong?
annakata
As for offensive, *I* find your conduct offensive - especially you're zealous mono-pole opinions about "truth" - ipso facto you are offensive. Perhaps you'd like a dictionary to look up "ipso facto"?
annakata
Speaking as a 3rd party here -- personally, I find Dimitre's suggestion to be the better practice except in cases where the user has explicit (and good) reason to care about tag name irrelevant of namespace; if anyone did this against a document which I was mixing in differently-namespaced content (presumably intended to be read by a different toolchain), I would consider their behavior very inappropriate. That said, the argument is -- as you suggest -- a bit unbecoming.
Charles Duffy
A: 

Not sure if this helps, but with XSL, I'd do something like:

<xsl:for-each select="a/b">
    <xsl:value-of select="c"/>
    <xsl:value-of select="d"/>
    <xsl:value-of select="e"/>
</xsl:for-each>

and won't this XPath select all children of B nodes:

a/b/*
Calvin
Thanks Calvin, but I'm not using XSL, and there are actually more elements underneath B which I don't want to select. I'll update my example to be clearer.
nickf
Oh, well in that case annakata seems to have the solution.
Calvin
+7  A: 

One correct answer is:

     /a/b/*[self::c or self::d or self::e]

Do note that another answer that still has some positive votes, its author initially removed it but later put it back again:

a/b/*[local-name()='c' or local-name()='d' or local-name()='e']

is both too-long and incorrect. This XPath expression will select nodes like:

  • OhMy:c

  • NotWanted:d

  • QuiteDifferent:e

Dimitre Novatchev