Xpath gets the last of the previous siblings

Something really simple here (at least I think), I just don't understand.

I need to parse a large XML document to get a specific node defined by one of its subnode values. So far it has been easy. But when I try to analyze farther from this node relatively up, choosing the predecessor siblings of my ancestor using the predicate, I get a list of nodes from which I have to go down again.

In theory, this is a table with 5 columns and two rows (in the example below). I get only the id element from one field and should find the name specified in the first field of the row. The first field is always of type “Link” and has the name of a subset with text - this is what you need to get.

In other words, I need to go from any node with <id>XXX_X</i> to the next cell of the previous cathedral using the xsi:type='Label' control xsi:type='Label' and the name node. From node <id>MyItemId_1</> I need to get the second previous-sibling, from node <id>MyItemId_4</id> I need to get the 5th previous-sibling.

This is an xml sample:

 <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 get the element I should get with this xpath:

 //cell[control[type='Link']]/control[type='Link' and selected='false' and id='MyItemId_3']/id 

This selects the identifier of the cell control, namely the 4th column in the second row of the displayed table.

From this node on, I am trying to go to the first cell in the row, following this path:

 ../../preceding-sibling::cell[control[@xsi:type='Label' and name[node()]]]/control[name[node()]]/name 

This gives me two correct cells in the first column of the table.

 <name>MyOtherItemName</name> * * * * * * * * * * <name>MyItemName</name> 

Now he has broken my back, since I can’t get him to simply return the last of the two selected to me.

I tried this:

 ../../preceding-sibling::cell[control[@xsi:type='Label' and name[node()]]][1]/control[name[node()]]/name 

which is the choice of the previous sibling with the predicate of exactly the kind of siblings that I am looking for, but it seems I can not combine this predicate with the selector [1]. Instead of selecting the desired first previous sibling “MyItemName”, he selects the first brother from all previous “MyOtherItemName”.

I need help, I hope that someone has a key and can identify me in the right direction.

Exactly what I created for this job is copying the xml to http://www.bit-101.com/xpath/ and working with the concatenated xpathes on it to mimic 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 
+6
source share
3 answers

I don’t understand what the problem is, but the previous brothers are sorted from the node itself to the beginning of the document, that is, vice versa than in the document. To get the closest previous brother, use preceding-sibling[1] , to get the farthest (ie, First in document order), use preceding-sibling[last()] .

+11
source

After reading your update will not work:

 //cell[control/id="MyItemId_4"]/preceding-sibling::cell[control[@xsi:type='Label'] and not(control/name='')][1] 

I'm a little unsure of the name of the node: do you want to check for text in the name of the node or just the existence of the name of the node itself?

+1
source

YourWebElement.FindElement (By.XPath ("front-sibling :: * [1]"));

Here, 1 indicates only the sibling above the selected node, and then you can do a recursion to get all previous siblings from the bottom up.

+1
source

Source: https://habr.com/ru/post/907800/


All Articles