Xpath writing example

Hi Katalon community,

I want to locate a td element by the text inside; however the text is separated by i elements inside td element.

<td> "first"

 <i></i>

  "second"

 <i></i>

 "third" 

  </td>

There are multiple tags on the webpage. If I write //td[contains(text(),‘first’)], it locates all of them. If I write the xpath such that it include the texts “first”, “second” and “third”, it would locate the exact td element. I tried //td[contains(text(),‘first’)][contains(text(),‘second’)][contains(text(),‘third’)]
However, this xpath does not work. Is there a way to write the xpath that includes all the text?

Any help would be appreciated.
Thanks : D

//td[contains(text(),‘first’)][contains(text(),‘second’)][contains(text(),‘third’)]

I find this XPath is OK. This is not a problem.

I guess you have a problem somewhere else, other than XPath syntax, in your Test Case script. For example, you do not wait for the page to load before trying to find the <td> element inside it.

Just use the ‘and’ operator:

//td[contains(text(),‘first’) and contains(text(),‘second’) and contains(text(),‘third’)]

hmm, for some reason, the ‘and’ operator that @Brandon_Hein suggested does not work. And the syntax suggested by @kazurayam also does not work. I tried copy and pasting both approaches and switching out the text.Maybe if I give more details; something can be found. I will also see if any of the devs in my company have any idea.

  <td>Workflow <i class="icon-caret-right muted">::before</i> Record <i class="icon-caret-right muted">::before</i> New</td>

The XPath that @Brandon_Hein suggested is equivalent to the one I suggested. Both failed. Then it proves that you have a problem in your test case other than XPath. For example, you do not wait for the page to load before trying to find the <td> element inside it. Do you do verifyElementPresent() in your test case? Please share the code of your test case.

Give this one a try:

//td[contains(normalize-space(), 'Workflow') and contains(normalize-space(), 'Record') and contains(normalize-space(), 'New')]

The idea here is to use the normalize-space() function as a predicate. This function considers not only the first text node found, but all child text nodes of the specified element.

Thanks @Brandon_Hein and @kazurayam! : D
The normalize-space approach worked for me :+1:t4:

This is an interest post for me. It motivated me to study in depth how XPath functions text(), contains() and normalize-space() work.

I have made a project on Github.

The sample code is here: https://github.com/kazurayam/XPathWritingExample/blob/master/Scripts/TC1/Script1558585003703.groovy

This code emits the folloing output:

tdWithMixedContent is '<td>Workflow <i class="icon-caret-right muted">::before</i> Record <i class="icon-caret-right muted">::before</i> New</td>'

# XPath text() functions returns a NodeList when applied to an HTML Element with mixed content
'count(//td/text())' returns 3.0
'//td/text()[1]' returns 'Workflow '
'//td/text()[2]' returns ' Record '
'//td/text()[3]' returns ' New'

# XPath contains(nodelist,pattern) function silently chooses only the 1st node of the nodelist given as 1st argument
'//td[contains(text(), "Workflow")]' returns true
'//td[contains(text(), "Record")]' returns false !!!
'//td[contains(text(), "New")]' returns false !!!

# you can choose a node out of the nodelist returned by text()
'//td[contains(text()[1], "Workflow")]' returns true
'//td[contains(text()[2], "Record")]' returns true
'//td[contains(text()[3], "New")]' returns true

# normalize-space() function scans the descendent nodes of the target element recursively for text contents, concatinates them to a string, normalizes white space characters
'normalize-space(//td)' returns 'Workflow ::before Record ::before New'

# it is convenient to call contains() with normalize-space() as the 1st argument
'//td[contains(normalize-space(), "Workflow")]' returns true
'//td[contains(normalize-space(), "Record")]' returns true
'//td[contains(normalize-space(), "New")]' returns true
'//td[contains(normalize-space(), "Workflow") and contains(normalize-space(), "Record") and contains(normalize-space(), "New")]' returns true
'//td[contains(normalize-space(.), "Workflow")][contains(normalize-space(.), "Record")][contains(normalize-space(.), "New")]' returns true

2019-05-24 10:27:30.121 INFO  c.k.katalon.core.main.TestCaseExecutor   - END Test Cases/TC1
2 Likes