XPath //div[contains(text(), 'string')] fails to select divs containing 'string'

49,325

Solution 1

Replace text() with string():

//div[contains(string(), "Elangovan")]

Or, you can check that span's following text sibling contains the text:

//div[contains(span/following-sibling::text(), "Elangovan")] 

Also see:

Solution 2

Alternatively to alecxe's correct answer (+1), the following slightly simpler and somewhat more idiomatic XPath will work the same way:

//div[contains(., "Elangovan")]

The reason that your original XPath with text() does not work is that text() will select all text node children of div. However, contains() expects a string in its first argument, and when given a node set of text nodes, it only uses the first one. Here, the first text node contains whitespace, not the sought after string, so the test fails. With the implicit . or the explicit string() first argument, all text node descendants are concatenated together before performing the contains() test, so the test passes.

Solution 3

To make @kjhughes's already good answer just a little more precise, what you're really asking for is a way to look for substrings in the div's string-value:

For every type of node, there is a way of determining a string-value for a node of that type. For some types of node, the string-value is part of the node; for other types of node, the string-value is computed from the string-value of descendant nodes.

Both the context node (. or the div itself) and the set of nodes returned by text() -- or any other argument! -- are first converted to strings when passed to contains. It's just that they're converted in different ways, because one refers to a single element and the other refers to a node-set.

A single element's string-value is the concatenation of the string-values of all its text node descendants. A node-set's string-value, on the other hand, is the string-value of the node in the set that is first in document order.

So the real difference is in what you're converting to a string and how that conversion takes place.

Share:
49,325
Admin
Author by

Admin

Updated on November 30, 2020

Comments

  • Admin
    Admin over 3 years

    This is the HTML code:

    <div>  <span></span>  Elangovan  </div>
    

    I want to write an XPath for the div based on its contained text. I tried

    //div[contains(text(),'Elangovan')]
    

    but this is not working.

  • alecxe
    alecxe over 9 years
    plus one, very detailed explanation!
  • kjhughes
    kjhughes over 9 years
    The string-value link and explanation provided by @lwburk are valuable contributions and worth understanding. +1
  • undefinedman
    undefinedman almost 6 years
    @alecxe you sir, are my hero! Finally I can select text like <p>Hello <strong>World</strong></p>