runr
runr

Reputation: 1146

XPath to get a full node except one child

The idea is very similar to the one asked about in this question and probably many others.

However, instead of extracting childs, I'm interested in the whole trimmed node. That is, the common solution is using

//node/*[not(self::a)]

instead of

//node/*

I'm looking for a way to apply the same logic of excluding a certain named branch, but extracting the node from a higher level: //node instead of //node/*.

What would be the appropriate syntax for this? //node[not(//node/a)] and similar doesn't seem to work.

example:

<root>
   <some_wrapper>
     <node>
       <a>
           <report key=1>
               <text>t</text>
           </report>
           <report key=2>
               <text>t</text>
           </report>
       </a>
       <b>
           <text>sample_text</text>
           <value>1</value>
       </b>
       <c>
           <text>sample_text</text>
           <value>2</value>
       </c>
     </node>
   </some_wrapper>
</root>

The goal is to find and select the whole node section, like when using //node, except that a child should not be included in the selection.

//node/*[not(self::a)] doesn't work, since it selects a list of childs in node, but not the whole node (if I'm using the terminology correctly).

Upvotes: 0

Views: 911

Answers (2)

Michael Kay
Michael Kay

Reputation: 163262

XPath always selects nodes that are present in the input document, unchanged. If you want to select a node named N, then //N will select that node; it returns, in effect, a reference to the node in the source document. If that node has children in the source document, then selecting it isn't going to remove those children.

Note that the XPath expression doesn't actually select the children. Many tools and applications that use XPath display the nodes selected by an XPath expression by serializing the whole XML subtree of those nodes, but that's a decision of the calling application (it could equally well display the result as a path containing the ancestors of the node, e.g. /root[1]/someWrapper[1]/node[2].)

If you want to create a modified copy of part of the source document, you need XSLT or XQuery for that, not XPath.

Upvotes: 2

supputuri
supputuri

Reputation: 14135

Here is the xpath to get all nodes (except the a) under some_wrapper.

//some_wrapper/descendant::*[not(name()='a' or ancestor::a)]

If you want to filter only the items under node tag then use the below.

//some_wrapper/descendant::*[not(name()='a' or ancestor::a) and (name()='node' or ancestor::node)]

Upvotes: 2

Related Questions