venusoft
venusoft

Reputation: 150

Find group of elements in recursive parent-child with XPath

I need to find a child node in a xml file which is inside a recursive parent-child attribute. Here is an xml sample:

<root>
    <element>
        <nodeA>
            <nodeB>
                <nodeA>
                    <nodeB>
                        <nodeA>
                            <nodeB></nodeB>
                            <nodeB></nodeB>
                            <nodeB></nodeB>         
                        </nodeA>
                    </nodeB>
                    <nodeB>
                        <nodeA>
                            <nodeB></nodeB>
                            <nodeB></nodeB>                     
                        </nodeA>            
                    </nodeB>
                    <nodeB>
                        <nodeA>
                            <nodeB></nodeB>                     
                        </nodeA>            
                    </nodeB>                        
                </nodeA>
            </nodeB>
            <nodeB>
                <nodeA>
                    <nodeB>
                        <nodeA>
                            <nodeB></nodeB>                     
                        </nodeA>
                    </nodeB>            
                </nodeA>            
            </nodeB>
        </nodeA>
    </element>
</root>

I can find all nodes without a nodeA child with:

//nodeB[not(nodeA)]

but I need to select the first (and only the first) nodeB group without a nodeA child, practically the first three occurences of nodeBin the example above.

Upvotes: 1

Views: 967

Answers (2)

CroWell
CroWell

Reputation: 616

Here is

(//nodeA)[nodeB[not(nodeA)]][1]/nodeB

Your XPath is almost right - you just need to UP on one level (to nodeA group) and choose first one. Note that XPath collection are 1-indexed instead of classic 0-indexed.

UPD: And round brackets to correctly control the priority of operators.

Upvotes: 1

Sentinel
Sentinel

Reputation: 6449

With the query you've already got you're only a couple steps away from what you want.

Starting with //nodeB[not(nodeA)] you want to go up one level to the parents /.., but you only want the parent of the first group (//nodeB[not(nodeA)]/..)[1] and of course you want the nodeBs without child nodeAs for the final result of:

(//nodeB[not(nodeA)]/..)[1]/nodeB[not(nodeA)]

Upvotes: 1

Related Questions