How to use XPath contains() here?
You are only looking at the first li
child in the query you have instead of looking for any li
child element that may contain the text, 'Model'
. What you need is a query like the following:
//ul[@class='featureList' and ./li[contains(.,'Model')]]
This query will give you the elements that have a class
of featureList
with one or more li
children that contain the text, 'Model'
.
I already gave my +1 to Jeff Yates' solution.
Here is a quick explanation why your approach does not work. This:
//ul[@class='featureList' and contains(li, 'Model')]
encounters a limitation of the contains()
function (or any other string function in XPath, for that matter).
The first argument is supposed to be a string. If you feed it a node list (giving it "li
" does that), a conversion to string must take place. But this conversion is done for the first node in the list only.
In your case the first node in the list is <li><b>Type:</b> Clip Fan</li>
(converted to a string: "Type: Clip Fan
") which means that this:
//ul[@class='featureList' and contains(li, 'Type')]
would actually select a node!
This is a new answer to an old question about a common misconception about contains()
in XPath...
Summary: contains()
means contains a substring, not contains a node.
Detailed Explanation
This XPath is often misinterpreted:
//ul[contains(li, 'Model')]
Wrong interpretation:Select those ul
elements that contain an li
element with Model
in it.
This is wrong because
contains(x,y)
expectsx
to be a string, andthe XPath rule for converting multiple elements to a string is this:
A node-set is converted to a string by returning the string-value of the node in the node-set that is first in document order. If the node-set is empty, an empty string is returned.
Right interpretation: Select those ul
elements whose first li
child has a string-value that contains a Model
substring.
Examples
XML
<r> <ul id="one"> <li>Model A</li> <li>Foo</li> </ul> <ul id="two"> <li>Foo</li> <li>Model A</li> </ul></r>
XPaths
//ul[contains(li, 'Model')]
selects theone
ul
element.Note: The
two
ul
element is not selected because the string-value of the firstli
childof thetwo
ul
isFoo
, which does not contain theModel
substring.//ul[li[contains(.,'Model')]]
selects theone
andtwo
ul
elements.Note: Both
ul
elements are selected becausecontains()
is applied to eachli
individually. (Thus, the tricky multiple-element-to-string conversion rule is avoided.) Bothul
elements do have anli
child whose string value contains theModel
substring -- position of theli
element no longer matters.