Use the Kayessian method of node-set intersection:
The intersection of two node-sets $ns1
and $ns2
is evaluated by the following XPath expression:
$ns1[count(.| $ns2)=count($ns2)]
If we have the following XML document:
then according to the question, we have:
$ns1
is:
/*/*[@class='header_completed'][1]
/following-sibling::*
$ns2
is:
/*/*[@class='header_completed'][1]
/following-sibling::*[@align='center'][1]
/preceding-sibling::*
We simply substitute $ns1
and $ns2
in the Kayessian formula and get the following XPath expression, which selects exactly the wanted 5 elements:
/*/*[@class='header_completed'][1]
/following-sibling::*
[count(.|/*/*[@class='header_completed'][1]
/following-sibling::*[@align='center'][1]
/preceding-sibling::*)
=
count(/*/*[@class='header_completed'][1]
/following-sibling::*[@align='center'][1]
/preceding-sibling::*)
]
To verify that this is really the solution, we use this XSLT transformation:
When this transformation is applied on the XML document above, the wanted correct result is produced:
XPath 2.0 solution:
In XPath 2.0 we can use the intersect
operator and the >>
and/or the <<
operators.
The XPath 2.0 expression that corresponds to the previously used XPath 1.0 expression is:
/*/*[ .
>>
/*/*[@class='header_completed'][1]
]
intersect
/*/*[ /*/*[@class='header_completed'][1]
/following-sibling::*[@align='center'][1]
>>
.
]
Here is an XSLT 2.0 solution, proving the correctness of this XSLT 2.0 expression:
when applied on the XML document defined before, we again get the same wanted, correct result: