Selenium Xpath to find a table cells inside a div tag

19,162

Wrong:

*//div[@id='AutoText']//td[contains[Text(), 'celltext']]
*//div[@id='AutoText']//table//tbody//tr[td//Text()[contains[., 'celltext']]

Correct (with shorter alternatives):

//div[@id='AutoText']//td[contains(text(), 'celltext')]
//div[@id='AutoText']//td[contains(., 'celltext')]

//div[@id='AutoText']/table/tbody/tr[td//text()[contains(., 'celltext')]
//div[@id='AutoText']/table/tbody/tr[td[contains(., 'celltext')]]
  • contains() is a function
  • text() needs to be lowercase
  • predicates can be nested
  • don't use // when you don't have to

Note

. refers to "this node" and, when given as an argument to a string function such as contains(), is the equivalent of string(.). This, however, is not at all the same as text().

string(.) creates the concatenation of all text nodes inside the current node, no matter how deeply nested. text() is a node test and by default selects only the direct children.

In other words, if the current node was <td>foo <b>bar</b> baz</td>, contains(text(), 'bar') would actually be false. (So would contains(text(), 'baz'), for a different reason.)

contains(., 'bar') on the other hand would return true, so would contains(., 'baz').

Only when the current node contains nothing but a single text node, text() and . are equivalent. Most of the time, you will want to work with . instead of text(). Set up your predicates accordingly.

Share:
19,162
Calle
Author by

Calle

Updated on June 05, 2022

Comments

  • Calle
    Calle almost 2 years

    I have the following HTML code that I need to check if text exists within a table cell:

    <div class="background-ljus" id="AutoText">
      <table class="topAlignedCellContent">
        <tbody>
          <tr>
            <td>X1</td>
          </tr>
          <tr>
            <td>X2</td>
          </tr> 
        </tbody>
      </table>
      <table>
        <tbody>
          <tr>
            <td>Y1</td>
            <td>Y2</td>
          </tr>
        </tbody>
      </table>
      <table>
        <tbody>
          <tr>
            <td>Z1</td>
            <td>Z2</td>
          </tr>
        </tbody>
      </table>
    </div>
    

    I have solved it like this:

    By locator = getLocator(CommonConst.XPATH, "*//div[@" + type + "='" + anyName + "']");
      fluentWait(locator);
    
      WebElement div = getDriver().findElement(locator);
      List<WebElement> cells = div.findElements(By.tagName("td"));
      for (WebElement cell : cells) {
        if (cell.getText().contains(cellText)) {
          foundit = true;
        }
      }
    

    But i think its a bit slow because I need to do this several times. I tried to do this with only XPath but had no luck.

    "*//div[@id='AutoText']//td[contains[Text(), 'celltext']]"
    "*//div[@id='AutoText']//table//tbody//tr[td//Text()[contains[., 'celltext']]"
    

    Anyone have a suggestion about why my XPath isn't working?