Select element and its descendants - xpath

I'm trying to select an folder and its descendants from a JCR with XPath. I can select the folder easily enough:
//content/documents/folder-name
I can select its descendants too:
//content/documents/folder-name//*
However, I can't figure out how to get both. I've tried several things. These select nothing:
//content/documents/folder-name | //content/documents/folder-name//*
//content/documents/folder-name(. | *)
//content/documents/folder-name/(. | *)
//content/documents/folder-name/descendant-or-self
//content/documents/folder-name/descendant-or-self::node()
These both throw a javax.jcr.query.InvalidQueryException:
//content/documents/folder-name[. | *]
//content/documents/folder-name/[. | *]
Obviously I'm terrible at XPath. Please help.
Edit: I was using the // prefix because I didn't realize I could use /jcr:root/content instead. I have the same problem with that, however.

You can combine two XPaths using the union operator:
xpath1 | xpath2
However, your first XPath,
//content/documents/folder-name
does select the folder-name element(s), which includes the descendants of the element.
If you want the folder-name elements to be first in a list, followed by their descendants, you could combine as follows:
//content/documents/folder-name | //content/documents/folder-name//*

//content/documents/folder-name/descendant-or-self::node() looks correct to me (without seeing your XML input), though //content/documents/folder-name/descendant-or-self::* is probably better.
Certainly if //content/documents/folder-name selects something then ``//content/documents/folder-name/descendant-or-self::*` should also select something.
In XPath 2.0 you can do //content/documents/folder-name/(.|descendant::*) but although it's shorter, it seems clumsier to me than using the descendant-or-self axis.

Related

XPath Combining/Multiple

I'm using XPath to select elements of content and i want to select 2 elements, the problem is I dont know how to combine the 2 selectors into 1 query.
//div[#id="dle-content"]/div[#class="mcontent_inner"]/div[#class="mcontent_inner_box"]/div[#class="article"]/img[#class=""]
//div[#id="dle-content"]/div[#class="mcontent_inner"]/div[#class="mcontent_inner_box"]/div[#class="article"]/div/div[#class="quote"]
I thought I could do this by doing;
//div[#id="dle-content"]/div[#class="mcontent_inner"]/div[#class="mcontent_inner_box"]/div[#class="article"]/img[#class=""] and //div[#id="dle-content"]/div[#class="mcontent_inner"]/div[#class="mcontent_inner_box"]/div[#class="article"]/div/div[#class="quote"]
or
//div[#id="dle-content"]/div[#class="mcontent_inner"]/div[#class="mcontent_inner_box"]/div[#class="article"]/img[#class=""] | //div[#id="dle-content"]/div[#class="mcontent_inner"]/div[#class="mcontent_inner_box"]/div[#class="article"]/div/div[#class="quote"]
But none of these work.
You forget the brackets:
This:
(//div[#id="dle-content"]/div[#class="mcontent_inner"]/div[#class="mcontent_inner_box"]/div[#class="article"]/img[#class=""]|//div[#id="dle-content"]/div[#class="mcontent_inner"]/div[#class="mcontent_inner_box"]/div[#class="article"]/div/div[#class="quote"])
should work.

Xpath | operator inside the path

I have an xpath as follows:
.//*[text()='Name:']/../child::select | .//*[text()='Name:']/../child::span
However for me it's not very compact nor elegant, I'd prefer something along the lines of:
.//*[text()='Name:']/../child::(select|span)
But the above solution does not work.
The idea is that the text (e.g. 'Name:' is passed as an argument to a function, and it returns the node that might be of type either select or span.
Would appreciate help greatly.
You can use the | operator with self:
.//*[text()='Name:']/../child::*[self::span | self::select]
The child:: is the default, so it could be shortened to
.//*[text()='Name:']/../*[self::span | self::select]

Selecting multiple results from XQUERY query

I am trying to select multiple columns from a query, but so far, I can only manage to select one. So I'm basically stuck with either selecting one, or all of them.
Here's my expression, what I got so far, which select only (1) column:
let $y := doc("http://en.wikipedia.org/wiki/List_of_deaths_on_eight-thousanders")//table[preceding-sibling::h2//span[string() = "K2"]][1]
return $y/tr/td[2]/string()
I would love some explanation of how one would go about doing this, since there's almost no documentation of this lovely language.
How would you like the result to be returned? You could construct new elements, or concatenate strings. There are many ways that this could be accomplished.
Here's one way to get comma-separated values:
return $y/tr/fn:string-join( (td[2] | td[4]), ", " )
You can try it on zorb.io.
Update
(td[2] | td[4]) selects both elements, and passes them, as a sequence, to fn:string-join(). | is the XQuery union operator (and can be substituted for the keyword).
As far as documention, the functx site documents the standard library (all fn-prefixed functions), and has useful examples. And the specs are surprisingly readable.

WebDriver locate element by combined xpath

Is there any way, how I can to identify two xpath values in one.
I have text located somewhere on web page, on another page it exists in same element, but has different xpath. See below two variants:
Variant1: .//*[#id='quote_1']/div[2]/div[1]/div[1]/div[1]/p[2]
Variant2: .//*[#id='quote_1']/div/div[1]/div[1]/div[1]/div[2]/div[3]/span[2]
I'm looking how I can combine these two xpath's to one like the following:
xpath = Variant1 or Variant2;
Thank you.
The XPath union operator | is probably what you are asking for:
.//*[#id='quote_1']/div[2]/div[1]/div[1]/div[1]/p[2]
|
.//*[#id='quote_1']/div/div[1]/div[1]/div[1]/div[2]/div[3]/span[2]
This XPath expressions selects the union of two nodesets:
All nodes selected by .//*[#id='quote_1']/div[2]/div[1]/div[1]/div[1]/p[2]
All nodes selected by .//*[#id='quote_1']/div/div[1]/div[1]/div[1]/div[2]/div[3]/span[2]

How to make one RxPath from two

I have those two RxPaths which I need to be written in one expresion:
/td[2]/a[1]/tag[1]
and
/td[2]/a[1]
So basically I need to select path with 'tag' element if exists, if not than to select 'a' element.
something like:
if exist /td[2]/a[1]/tag[1] select /td[2]/a[1]/tag[1]
else select /td[2]/a[1]
Those elements need to have innertext attribute with some value in them, so I tried:
/td[2]/descendant::node()[#innertext!='']
but it won't work...
Also those elements are at the bottom of hierarchy so if is there any way to just select first element at lowest level.
I managed to solve this with an regex at the end of my Xpath expression.
/dom/body/div[#id='isc_0']/div/div[#id='isc_B']/div[#id='isc_C']/div[#id='isc_10']/div/div/iframe/body/table/tbody/tr/td[1]/a[#innertext='any uri item']/../../td[2]/*[#innertext~'[^ ]+']
Sorry for misunderstanding with problem...
Regards,
Vajda Vladimir
So basically I need to select path
with 'tag' element if exists, if not
than to select 'a' element. something
like:
if exist
/td[2]/a[1]/tag[1]
select
/td[2]/a[1]/tag[1]
else select
/td[2]/a[1]
I highly doubt that the top element of the document is a td. Don't use /td -- it means you want to select the top element of the document and this top element must be a td .
Also, /td[2] never selects anything, because a (wellformed) XML document has exactly one top element.
Use:
someParentElement/td[2]/a[1]/tag[1]
|
someParentElement/td[2]/a[1][not(someParentElement/td[2]/a[1]/tag[1])]
Those elements need to have innertext
attribute with some value in them
Use:
someParentElement/td[2][.//#innertext[normalize-space()]]/a[1]/tag[1]
|
someParentElement/td[2]
[.//#innertext[normalize-space()]]/a[1]
[not(someParentElement/td[2]
[.//#innertext[normalize-space()]]/a[1]/tag[1])]
Also those elements are at the bottom
of hierarchy so if is there any way to
just select first element at lowest
level.
This is not clear. Please, clarify.
All "leaf" elements can be selected using the following XPath expression:
//*[not(*)]
The elements selected don't have any children-elements, but may have other children (such as text-nodes, PIs, comments) and attributes.
Besides all those good advices from #Dimitre, I want to add that a parent will always come before (in document order) than a child, so you could use this XPath expression:
(/real-path-from-root/td[2]/a[1]
|
/real-path-from-root/td[2]/a[1]/tag[1])[last()]
You could do this without | union set operator in XPath 1.0, but it will end up very unreadable... Of course, in XPath 2.0 you could just do:
(/real-path-from-root/td[2]/a[1]/(.|tag[1]))[last()]

Resources