Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

xpath get last of specific preceding-sibling

Tags:

xml

xpath

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 of xsi: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
like image 819
Oliver Friedrich Avatar asked Feb 06 '12 20:02

Oliver Friedrich


People also ask

How can I get next sibling in XPath?

To traverse to the next sibling, we have to use the following-sibling concept in xpath. This will allow us to traverse to the next sibling from the present sibling of the same parent. Let us try to move from the first child<h1> of parent <div> to the second <h2> as in the above image.


1 Answers

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()].

like image 52
choroba Avatar answered Oct 12 '22 14:10

choroba