Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

XPath to select multiple tags

Tags:

xml

xpath

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

Is this possible?

like image 915
nickf Avatar asked Apr 06 '09 15:04

nickf


People also ask

How do you locate multiple elements with the same XPath?

For example if both text fields have //input[@id='something'] then you can edit the first field xpath as (//input[@id='something'])[1] and the second field's xpath as (//input[@id='something'])[2] in object repository.

How do I select the second element in XPath?

//div[@class='content'][2] means: Select all elements called div from anywhere in the document, but only the ones that have a class attribute whose value is equal to "content". Of those selected nodes, only keep those which are the second div[@class = 'content'] element of their parent.

How do I combine two Xpaths?

The | character denotes the XPath union operator. You can use the union operator in any case when you want the union of the nodes selected by several XPath expressions to be returned.


2 Answers

One correct answer is:

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

Do note that this

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
like image 59
Dimitre Novatchev Avatar answered Oct 12 '22 21:10

Dimitre Novatchev


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.

like image 43
annakata Avatar answered Oct 12 '22 20:10

annakata