Reputation: 4501
I'm dealing with some gnarly HTML. Here's a stylized example of the ancestry of a given element:
/html/body/foo/bar/baz/quux/b
I have a reference to body
in my code and b
is the context element for my XPath query. In the above example how do I find foo
? More descriptively, how do I find the first element in a given ancestry which is the child of another given element? The elements between body
and b
are unknown and varied in type and depth at runtime. I can do this outside of XPath by iterating over the ancestors from b
until I get to body
but I'm wondering if there's some XPath ancestor magic to find this relative reference.
Upvotes: 2
Views: 4341
Reputation: 243479
Use:
ancestor::body[1]/foo
this selects the element that is the first element child of body
that is the first ancestor body
of the context node.
Even if you know that there are no nested body
elements, the above is slightly more efficient than:
ancestor::body/foo
because evaluating this last expression, all ancestors will be tested for being a body
.
UPDATE:
In a comment the OP clarified:
Well, I'm trying to find the intersection of the two sets (ancestors of context node, children of body)
In XPath 1.0 this is q direct substitution into the well-known Kayessian formula for node-set intersection:
$ns1[count(.|$ns2) = count($ns2)]
In this case we substitute $ns1
with ancestor::*
and $ns2 with /*/body/*
:
ancestor::*[count(. | /*/body/*) = count(/*/body/*)]
In XPath 2.0 this is easier, using the intersect
operator:
ancestor::* intersect /*/body/*
Upvotes: 2
Reputation: 12514
Without testing it, I would guess that ancestor::body/*[1]
might do it.
Explanation: ancestor::body
is the first body
element along the ancestor
'axis', /*
selects all of the children of that element, and [1]
selects the first element of that list of children, which in this case is foo
.
Upvotes: 2