TAGS :Viewed: 6 - Published at: a few seconds ago

[ XPath can't get whole tree for matching child ]

Given this XML:

<Orders>
    <Order>
        <Item name="xyz"/>
    </Order>
    <Order>
        <Item name="123"/>
    </Order>
</Orders>

Why does /Orders/Order[Item[@name='123']] return:

<Order>
    <Item name="123" />
</Order>

But /Orders[Order[Item[@name='123']]] returns:

<Orders>
    <Order>
        <Item name="xyz" />
    </Order>
    <Order>
        <Item name="123" />
    </Order>
</Orders>

In this second scenario the matching on name is ignored.

What XPath do I need to get back:

<Orders>
    <Order>
        <Item name="123" />
    </Order>
</Orders>

Answer 1


The reason the second example returns what it does is because your expression

/Orders[Order[Item[@name='123']]]

says:

  1. Locate an Orders node
  2. That contains an Order nmde
  3. That contains an Item node
  4. Where that Item node has an attribute name with value 123

Notice that you focus on the Orders node, so that is what is returned, i.e. the entire Orders node.

What you want does not exist in the source document, so you are asking for a transformation to occur. My XPath is somewhat rusty but I don't believe XPath by itself is capable of doing this. You will probably need to use XSLT to transform the XML to what you need.

Answer 2


Short answer is, given the XML posted, you can't get that output using XPath.

XPath is meant for locating part of an XML (XPath 1.0 especially). Notice that opening-tag, content, and corresponding closing-tag is considered one unit, an element node. So, such <Orders> element which contains only one <Order> child element that you expect to return is not part of the original XML, hence can't be returned using XPath.

XPath is a language for addressing parts of an XML document, designed to be used by both XSLT and XPointer. [Reference: XPath 1.0 Spec]