6

In XPath 1.0, how can I select all descendant nodes C of current (context) node A, that are not contained in an intervening node of type B?

For example, find all <a> links contained in the current element, that are not inside a <p>. But if the current element is itself inside a <p>, that's irrelevant.

<p>                   <—— this is irrelevant, because it's outside the current element
    ...
    <div>             <—— current element (context node)
        ...
        <a></a>       <—— the xpath should select this node
        ...
        <p>
            ...
            <a></a>   <—— but not this, because it's inside a p, which is inside context
            ...
        <p>
        ...
    </div>
    ...
</p>

The ... in the example could be several depths of intervening nodes.

I'm writing XSLT 1.0, so the additional functions generate-id(), current(), and such are available.

2
  • Something like /p/div/a ? And this is duplicate of stackoverflow.com/questions/15818191/… Commented Aug 28, 2015 at 13:37
  • 1
    @fukanchik no, I'm already in the div (current context node) and I need to select all a that are not inside a p, possibly with several middle nodes in between, for example several levels of div in between. Commented Aug 28, 2015 at 13:38

1 Answer 1

6

This is one possible XPath :

.//a[not(ancestor::p/ancestor::* = current())]

This XPath checks if current descendant a element doesn't have ancestor p which ancestor is current context node. In other words, it checks if the a element doesn't have ancestor p intervening between the a and the current context node.

Sign up to request clarification or add additional context in comments.

5 Comments

That makes sense, but is the = doing the right thing there? Don't I need something like .//a[not(ancestor::p/ancestor::*[generate-id(.) = generate-id(current())])] ?
@Tobia Sorry, I'm not sure my self if the expression will compare the element's value or compare the elements by reference (which I hope it to do)
I don't think it's right, because "If both objects to be compared are node-sets, then the comparison will be true if and only if there is a node in the first node-set and a node in the second node-set such that the result of performing the comparison on the string-values of the two nodes is true." source
Still, either your expression or my generate-id() variant will do. Thanks!
why start with .// rather than // ?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.