26

Can anyone please help me how to use contains in my xpath? My xpath changes all the time when users are added, so I can't find element using xpath.

This is my xpath:

.//*[@id='contentText']/table/tbody/tr[2]/td/table/tbody/tr/td[1]/table/tbody/tr[9]/td/table/tbody/tr/td[1]/strong[2]

Changes when new user added:

.//*[@id='contentText']/table/tbody/tr[2]/td/table/tbody/tr/td[1]/table/tbody/tr[10]/td/table/tbody/tr/td[1]/strong[2]

Please help me how to get it done.

1
  • Share you HTML and element you are trying to locate.
    – olyv
    Nov 25, 2014 at 7:20

8 Answers 8

33

I have tested an ExtJS application. Most of the page element attributes are dynamic. They change not only when you add a new user or something, they change every time when you open the application.

I have found the xpath expressions I get from the tools (Firebug etc.) is not very useful. Here is why:

  1. hard to read
  2. break easily
  3. hard to debug

What I do instead, is rather to spend time looking at the HTML and identify possible unique attributes that are not dynamic and come up with my own expressions. If none of the attributes are static for a certain element, use any other element on the page that does have static attributes with the parent/child/sibling relations to locate.

I often use "contains", but there are more. Here are some examples:

  • multiple condition: //div[@class='bubble-title' and contains(text(), 'Cover')]
  • partial match: //span[contains(text(), 'Assign Rate')]
  • starts-with: //input[starts-with(@id,'reportcombo')]
  • value has spaces: //div[./div/div[normalize-space(.)='More Actions...']]
  • sibling: //td[.='LoadType']/following-sibling::td[1]/select"
  • more complex: //td[contains(normalize-space(@class), 'actualcell sajcell-row-lines saj-special x-grid-row-collapsed')]

Take a look at the W3C XSL Functions page for some more ideas.

Edit: Link updated. Edit 2: XPATH changed

3
  • Great examples! I'm using similar methods for automating a JSF app with a lot of dynamic forms. I've found the W3C specification very useful. Feb 10, 2015 at 22:09
  • What a pleasure to know that someone out there has walked the same path! Thank you!
    – hxin
    Feb 25, 2015 at 1:43
  • 1
    The previous W3C specification link is not working now. Please refer to this page instead.
    – hxin
    Feb 6, 2017 at 22:26
4

You should be splitting the xpath to fetch individual tables for clarity sake.

I suggest the following:

// Get the content or container    
WebElement content = driver.findElement(By.id("contentText"));

//Get the table of users
WebElement tblUsers = content.findElement(By.xpath(".//table/tbody/tr[2]/td/table/tbody/tr/td[1]/table"));

// Get the rows which change always as and when users are added
WebElement allUsers = tblUsers.findElements(By.xpath(".//tbody/tr"));

// Loop through each row of users table
for(WebElement user : allUsers) {

   // Get the username
   WebElement username = user.findElement(By.xpath(".//td/table/tbody/tr/td[1]/strong[2]"));
   System.out.println("Username: " + username.getText());
}
1
  • 1
    this doesn't really provide any example on how to use contains Feb 10, 2015 at 21:57
4

We can use something like

By.xpath("//td[contains(text(),'youruser')]") //here user text is case sensitive

By.xpath("//td[contains(lower-case(text()),'youruser')]") //to handle case sensitivity. Here user is not case sensitive

2
.//*[@id='contentText']/table/tbody/tr[2]/td/table/tbody/tr/td[1]/table/tbody/tr[10]/td/table/tbody/tr/td[1]/strong[2]

That XPath should be drastically shortened. That is likely to fail if you are testing in different browsers and if anything ever changes on the page it could throw a false positive due to it looking at the wrong element. I recommend looking up "Relative XPaths" and also "XPath Axes", but I could demonstrate a better XPath for you if you posted a screenshot of the HTML and the web page.

Based on what you posted, you could do something like: //table[@id ='something' or @class='Something that identifies this specific table']//tr[contains(text(), 'something to identify the row') or ./text() = 'Exact Text Match']//strong[2]

Usually with table rows I end up identifying the row based on the text from a cell within the row. //table[@id ='something' or @class='Something that identifies this specific table']//tr[.//td[contains(text(), 'something to identify the row') or ./text() = 'Exact Text Match']]//td//strong[2][contains(text(), 'Partial Text Match') or ./text() = 'Exact Text Match']

0

Please try below code:

public List<WebElement> getText(String xpath) throws Exception {
    return driver.findElements(By.xpath(xpath)).getText();
}

if(tool.getText("//\*[@id='contentText']//\*/table//\*/strong").contains("<yourtext>"))
{
    system.out.println("Your text is available in the particular xpath");
} else {
    system.out.println("Your text is not available in the particular xpath");
}

It is working fine for me. I can find any text on any xpath using above code.

0

The 2 of your XPath changes from tr[9] to tr[10]. It seems that the number of the 3rd "tr" means user number.

In my practice delete that number can extract all users' data from HTML.(tested by RSelenium + rvest):

.//*[@id='contentText']/table/tbody/tr[2]/td/table/tbody/tr/td[1]/table/tbody/tr/td/table/tbody/tr/td[1]/strong[2] 
0

Although many answers are already present you can also refer the below links:

https://medium.com/edureka/xpath-in-selenium-cd659373e01a

XPath CheatSheet

-1

XPATH

driver.findElement(By.xpath("/html/body/div/input[1]")).sendKeys("123");

driver.findElement(By.xpath("//input[1]")).click();

driver.findElement(By.xpath("(//input[1])[4])")).click();

driver.findElement(By.xpath("//tag[@AN='AV']")).sendKeys("123");

driver.findElement(By.xpath("//tag[text()='AV']")).sendKeys("123");

driver.findElement(By.xpath("//tag[@AN='AV' and @AN='AV']")).click();




driver.findElement(By.xpath("//tag[contains(text(),'usrn')]").getText();

driver.findElement(By.xpath("//tag[contains(@AN,'usrn')]").getText();

driver.findElement(By.xpath("//tag[starts-with(text(),'usrn')]").getText();
driver.findElement(By.xpath("//tag[starts-with(@AN,'usrn')]").getText();

ex : //input[starts-with(@id,'reportcombo')]

Not the answer you're looking for? Browse other questions tagged or ask your own question.