xpath get last of specific preceding-sibling
Solution 1
I do not understand what the problem exactly is, but preceding-siblings are sorted from the node itself towards the beginning of the document, i.e. the other way round than in the document. To get the nearest preceding sibling, use preceding-sibling[1]
, to get the farthest one (i.e. the first one in the document order), use preceding-sibling[last()]
.
Solution 2
After reading your update, wouldn't this work:
//cell[control/id="MyItemId_4"]/preceding-sibling::cell[control[@xsi:type='Label'] and not(control/name='')][1]
I'm a bit unsure about the name node: do you want to test for existence of text in the the name node or just existence of the name node itself?
Solution 3
YourWebElement.FindElement(By.XPath("preceding-sibling::*[1]"));
Here 1 indicates just the sibling above the selected node and then you can do recursion in order to get all the preceding siblings from bottom to top.
![Oliver Friedrich](https://i.stack.imgur.com/4Qf5j.jpg?s=256&g=1)
Oliver Friedrich
Updated on July 21, 2022Comments
-
Oliver Friedrich almost 2 years
Here's something really simple (at least I guess), I just do not get the clue.
I have to parse a large XML document to get a specific node, identified by one of its subnode values. Thats easy so far. But when I try to parse onward from that node relatively upward, selecting the preceding-siblings of its ancestor by using a predicate I get a list of nodes, from that on I have to walk downward again.
In Theorie, that is a table, with 5 columns and two rows (in the shown example below). I get just the id element of one field, and need to find the name given in the first field of the row. The first field is always of type 'Link' and has a name subnode with text - which is the thing to get.
In other words, I need to move from any node with an
<id>XXX_X</i>
to the next preceding-sibling cell with a control ofxsi:type='Label'
and a name node. From the node<id>MyItemId_1</>
I need to get the second preceding-sibling, from the node<id>MyItemId_4</id>
I need to get the 5th preceding-sibling.This is a sample xml piece:
<cell> <control xsi:type="Label"> <id>1234</id> <name>MyOtherItemName</name> <message/> </control> <selected>false</selected> <style>Odd</style> </cell> <cell> <control xsi:type="Label"> <id>MyOtherItemId_0</id> <name/> <message/> </control> <selected>false</selected> <style>Odd</style> </cell> <cell> <control xsi:type="Label"> <id>MyOtherItemId_1</id> <name/> <message/> </control> <selected>false</selected> <style>Odd</style> </cell> <cell> <control xsi:type="Button"> <id>MyOtherItemId_2</id> <name>552</name> <message/> <type>Link</type> <selected>false</selected> </control> <selected>false</selected> <style>Odd</style> </cell> <cell> <control xsi:type="Button"> <id>MyOtherItemId_3</id> <name>432</name> <message/> <type>Link</type> <selected>false</selected> </control> <selected>false</selected> <style>Odd</style> </cell> <cell> <control xsi:type="Button"> <id>MyOtherItemId_4</id> <name>33</name> <message/> <type>Link</type> <selected>false</selected> </control> <selected>false</selected> <style>Odd</style> </cell> <cell> <control xsi:type="Label"> <id>1234</id> <name>MyItemName</name> <message/> </control> <selected>false</selected> <style>Odd</style> </cell> <cell> <control xsi:type="Label"> <id>MyItemId_0</id> <name/> <message/> </control> <selected>false</selected> <style>Odd</style> </cell> <cell> <control xsi:type="Label"> <id>MyItemId_1</id> <name/> <message/> </control> <selected>false</selected> <style>Odd</style> </cell> <cell> <control xsi:type="Button"> <id>MyItemId_2</id> <name>552</name> <message/> <type>Link</type> <selected>false</selected> </control> <selected>false</selected> <style>Odd</style> </cell> <cell> <control xsi:type="Button"> <id>MyItemId_3</id> <name>432</name> <message/> <type>Link</type> <selected>false</selected> </control> <selected>false</selected> <style>Odd</style> </cell> <cell> <control xsi:type="Button"> <id>MyItemId_4</id> <name>33</name> <message/> <type>Link</type> <selected>false</selected> </control> <selected>false</selected> <style>Odd</style> </cell>
I do get the item i have to get with this xpath:
//cell[control[type='Link']]/control[type='Link' and selected='false' and id='MyItemId_3']/id
That selects the id of the control of the cell, namely the 4th column in the second row, of the rendered table.
From that node on I try moving to the first cell in the row by following this path:
../../preceding-sibling::cell[control[@xsi:type='Label' and name[node()]]]/control[name[node()]]/name
That gives me the two correct cells of the first column of the table.
<name>MyOtherItemName</name> * * * * * * * * * * <name>MyItemName</name>
Now it breaks my back since I can't get it to just give me back the last one of the two selected.
I tried this:
../../preceding-sibling::cell[control[@xsi:type='Label' and name[node()]]][1]/control[name[node()]]/name
which is a preceding-sibling selection with a predicate to exactly the sort of siblings I search for, but it seems I can not combine that predicate with a [1] selector. Instead of selecting the desired first preceding sibling "MyItemName" it selects the first sibling from all preceding ones "MyOtherItemName".
I need help, hope someone here has a clue and can pinpoint me in the right direction.
Exactly what I set up to get this work is copying the xml into http://www.bit-101.com/xpath/ and working with the concatenated xpathes on it to simulate what the software should do:
//cell[control[type='Link']]/control[type='Link' and selected='false' and id='MyItemId_3']/id/../../preceding-sibling::cell[control[@xsi:type='Label' and name[node()]]]/control[name[node()]]/name
-
Oliver Friedrich over 12 yearsthat is right, but how do I use the selection of the first sibling only from those preceding siblings with that match the predicate? using preceding-sibling[PREDICATE][1] does not work - returns no node
-
Oliver Friedrich over 12 yearsthis does not work if I try it with bit-101.com/xpath. simply nothing gets selected. The first part, before the preceding-sibling works in this example.
-
Oliver Friedrich over 12 yearsI need to test for the name node to exist and have text.
-
Oliver Friedrich over 12 yearsplease try it out with bit-101/xpath, it won't work, if you mix predicate with selector.
-
forty-two over 12 yearsJust tried it in bit-101. It works for me and selects cell with name "MyOtherItemName"
-
choroba over 12 yearsIt does not work with bit-101, but it works with xsh: xsh.sourceforge.net
-
Oliver Friedrich over 12 yearssorry, but i choose bit-101 because it behaved similar to the xml-engine i have to use - the one in SilkPerformer. Maybe xsh uses xpath2?
-
Oliver Friedrich over 12 yearsyes, but it should show "MyItemName" because "MyItemId_4" is selected before.
-
forty-two over 12 yearsHmm, it selects "MyItemName" when I try it in eclipse, but "MyOtherItemName" in bit-101. I'd say bit-101 is in error.
-
choroba about 7 years@OliverFriedrich: It doesn't (I must know, I maintain it).