2015-04-28

Nested predicates in XPath and the need (or lack of) to reference an outer context from within

Key message: At least in my case, the depth cross-reference ended up not being needed at all. I could come up with a logic where the nested tests cascaded perfectly without any cross-reference from within to the outer context.

Given the following XML:

<Root>
  <Order ID="o1">
    <Purchase ID="p1"/>
    <Invoice ID="i1">
      <Item ID="it1" PurchaseID="p1"/>
      <Transaction ID="t1" ItemID="it1"/>
    </Invoice>
    <Invoice ID="i2">
      <Transaction ID="t2" ParentID="t1"/>
    </Invoice>
  </Order>
  <Order ID="o2">
    <Purchase ID="p2"/>
    <Invoice ID="i3">
      <Item ID="it2" PurchaseID="p2"/>
      <Transaction ID="t3" ItemID="it2"/>
    </Invoice>
  </Order>
</Root>

I needed to select all Transaction nodes from the Order with a Purchase whose ID was "p1".

In this example it should return two nodes, but note that the second node is farther away from the Purchase ID than the first one. In fact, it requires passing through the first node to get to it.

The XPath that solves this riddle is:

1: /Root/Order/Invoice/Transaction[
2:     @ItemID=../Item/[@PurchaseID="p1"]/@ID
3:   or
4:     @ParentID=../../Invoice/Transaction[
5:         @ItemID=../Item[@PurchaseID="p1"]/@ID
6:     ]/@ID
7: ]

In line 5, the XPath gets into a predicate depth of 3 levels, each one selecting the appropriate node from within to out.

No comments:

Post a Comment