André Levy
André Levy

Reputation: 329

How to return xpath union of nodes in separate trees?

It's a basic question, but I couldn't find the answer anywhere.

<a>
    <b1>
        <d1>D1</d1>
        <e1>E1</e1>
    </b1>
    <b2>
        <c2>
            <d2>D2</d2>
            <e2>E2</e2>
        </c2>
    </b2>
</a>

From the above I'd like to return:

<a>    
    <d1>D1</d1>
    <e1>E1</e1>
    <d2>D2</d2>
    <e2>E2</e2>
</a>

And not:

<a>
    <b1>
        <d1>D1</d1>
        <e1>E1</e1>
    </b1>
    <b2>
        <d2>D2</d2>
        <e2>E2</e2>
    </b2>
</a>

If that makes any sense. I tried "/a", but that gave me:

<a>
    <b1>
        <d1>D1</d1>
        <e1>E1</e1>
    </b1>
    <b2>
        <c2>D2E2</c2>
    </b2>
</a>

Upvotes: 1

Views: 513

Answers (2)

Michael Kay
Michael Kay

Reputation: 163418

XPath can only return nodes that are already present in your source tree. To construct new nodes, or reorganise the tree, you need XSLT or XQuery.

Upvotes: 3

har07
har07

Reputation: 89305

If you meant to select all leave nodes (nodes without child node(s)), you can try this XPath :

//*[not(*)]

Or using XPath union (|) to get child nodes of <b1> and <c2> :

(//b1/* | //c2/*)

Given sample XML you posted, both XPath above will return :

<d1>D1</d1>
<e1>E1</e1>
<d2>D2</d2>
<e2>E2</e2>

But if you really need the result to be wrapped in <a>, then I agree with @minopret comment, that isn't what XPath meant to do. XSLT is more proper way to transform an XML to different format.

UPDATE :

In respond to your last comment, there is no such grouping in XPath. Should be done in the host language if you need that data structure. Your best bet is to select parent of those desired nodes in XPath so you get them grouped by their parent. Then you can do further processing in the host language, for example :

//*[not(*)]/parent::*
//*[*[not(*)]]

Any of above two XPath queries can return :

<b1>
    <d1>D1</d1>
    <e1>E1</e1>
</b1>
<c2>
    <d2>D2</d2>
    <e2>E2</e2>
</c2>

Upvotes: 3

Related Questions