i want only the input elements that are within the <b> tag. the xpath
needs to ignore the input elements that are within <c> and <d> tags
Use:
//b//input
I need an xpath that fetches all the elements of a particular element
type, say input, that occurs before the first occurrence of another
element. the problem is, there is no proper hierarchy between the
targeted elements and the 'another element'. and there can be any
number of 'another element' present in the html.
This is not equivalent to the first requirement quoted above.
You don't specify what is mean't by "another element" but combining the two quoted requirements, and the provided source xml document, one can logically conclude that "another element" here means any following sibling of the element /a/b[1]
These will be selected by:
(//b)[1]//input
or for the provided xml document just:
/a/b[1]//input
If the document had more than one /a/b elements and you wanted to get the input descendants of only these /a/b/ elements that precede any /a/{X} elements, where {X} is a name different from b, use:
/a/b[not(preceding-sibling::*[not(self::b)])]//input
Finally, in the most general case, if you want to select the input descendants of only such b elements that come **before* any other (non-b) element (excluding the top element -- if the top element is a b then any input descendant of the top element satisfies the requirement, here is one XPath expression that selects these:
/*//b[not(ancestor::*[not(self::b) and parent::*])
and not(preceding::*[not(self::b)])]
//input
Here we use the fact that if an element x is before (in document order) an element y, then x is either an ancestor of y (belongs to itsancestor::* axis) or is a preceding element (belongs to its preceding::* axis)
XSLT-based verification:
This transformation evaluates all 5 XPath expressions and outputs the selected nodes:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<xsl:copy-of select="//b//input"/>
==================================
<xsl:copy-of select="(//b)[1]//input"/>
==================================
<xsl:copy-of select="/a/b[1]//input"/>
==================================
<xsl:copy-of select="/a/b[not(preceding-sibling::*[not(self::b)])]//input"/>
==================================
<xsl:copy-of select=
"/*//b[not(ancestor::*[not(self::b) and parent::*])
and not(preceding::*[not(self::b)])]
//input"/>
</xsl:template>
</xsl:stylesheet>
When applied on the originally-provided XML document:
<a>
<b>
<input>zyx</input>
<div>abc</div>
<span>def</span>
<input>ghi</input>
</b>
<c>
<div class="SameAttribute">Test</div>
<input>jkl</input>
<div>mno</div>
</c>
<d>
<div class="SameAttribute">Test</div>
<input>pqr</input>
<div>stu</div>
</d>
</a>
the wanted, correct result is selected when evaluating each expression:
<input>zyx</input>
<input>ghi</input>
==================================
<input>zyx</input>
<input>ghi</input>
==================================
<input>zyx</input>
<input>ghi</input>
==================================
<input>zyx</input>
<input>ghi</input>
==================================
<input>zyx</input>
<input>ghi</input>