Dynamic x-path: How to create in different ways
- mohdmyyusuf
- Jul 16, 2021
- 5 min read
Updated: Mar 28, 2023
Sometimes we face the situation when we are unable to find an element because the element does not have proper attributes. In such cases we create the dynamic xpath to locate an element on a web page. We have tried to enlist all possible ways to create dynamic xpath to locate such elements.
Creating the xpath on the basis of multiple attributes: If we are required to use multiple attributes of a tag to create the xpath we can use 'and' or 'or' operators. The other way to to use the multiple tags, just capture them in different square boxes and it will work like 'and' operator like //tagname[@oneAttribute = 'value'][@secondAttribute = 'value'] if we want to write and or OR operators we can write like this:
//tagname[@oneAttribute = 'value' and @secondAttribute = 'value']
//tagname[@oneAttribute = 'value' or @secondAttribute = 'value']
1. Preceding: It selects all the elements which are before the conditions mentioned. If we write [condition or the element]//preceding::input it says that it will search all inputs which fall before the element or condition in the beginning. Suppose there is a button with type = reset and there are some inputs(input html tags) before it on the page.
<div>
<input type = 'text'>Name</input>
<input type = 'text'>email</input>
<input type = 'submit'>Submit</input>
<input type = 'reset'>Clear</input>
</div>So if we create an xpath as follows: //*[@type='reset']//preceding::input
It will select all the input tags on the page which fall before the button with type = reset. Means there are three input tags before input with type = reset, so all the three will be searched.
2. following-sibling: It selects the element which is on the same level(sibling) and comes after the element. If we write [condition or the element]//following-sibling::input it says that it will search all input tags which are on the same level of the element in the square bracket and comes after it.
Suppose we have two buttons and the type of them are "submit" and "reset" respectively. First submit and then reset comes on the page. It means reset is a following-sibling of submit. See the html code below here two input tags are there on the same level.
<div>
<input type = 'submit'>Submit</input>
<input type = 'reset'>Clear</input>
</div>So we need to write xpath as follows: //*[@type='submit']//following-sibling::input
It will search the input tag on the same level of submit button but coming after it.
3. Parent: It selects the immediate parent tag of an element of a webpage. If we write //button[@id='test-element']//parent::div it will search for a "div" which is the immediate parent of button with id = test-element. If we write like //button[@id='test-element']//parent::* it will identify all parents of the tag. If we write like //button[@id='test-element']/.. then it will also point to the parent of the element.
4. Child: It selects all the children tags of an element of a webpage which match the search criteria. If we write //ul[@id ='test-element']//child::li, it will search for a "li" tags which are the children parent of <ul> with id = test-element.
5. Self: It selects to itself only, if axes "self" is used If we write //ul[@id ='test-element']//self::ul, it will search for a "ul" tags which is referring to itself.
6. Descendant: xpath axes "descendant" selects all the descendants at any level. It selects children grand children all the way below it. See the html below:
<table id="contactList">
<tbody>
<tr>
<th></th><th>Contact</th><th>Country</th><th>Salary</th><th></th>
</tr>
<tr>
<td><input type="checkbox"></td>
<td>Maria Anders</td>
<td>Germany</td> <td>5000</td>
<td><a href="https://mohdmyyusuf.wixsite.com/testinggeeks/post/selenium-advanced-concepts#">Click</a></td>
</tr>Tag table have multiple child elements which include <tbody>, <tr>, <td> etc. If we write: //table[@id = 'contactList']/descendant::td, it will select all the <td> tags below or under <table> tag.
Descendant can be applied in two ways one is descendant and another is descendant-or-self. The descendant selects all the children at any level which match the search criteria. The descendant-or-self includes all the children at any level which match the search criteria including the tag itself. It can be written like:
//table[@id = 'contactList']/descendant-or-self::td. This xpath will search all the descendant and itself also.
7. Ancestor: It selects all the ancestor tags of the current tag if they match the search criteria. It selects from all levels like parent tag, grand parent and all. See the html code below:
<table id = "contactList">
<tbody>
<tr>
<td>
<input type="checkbox">
</td>
<td>Mohd Yusuf</td>
<td>India</td>
<td>50000</td>
<td><a href="https://mohdmyyusuf.wixsite.com/testinggeeks/post/selenium-advanced-concepts#">Click</a></td>
</tr>If we write the xpath like //input[@type = 'checkbox']//ancestor::table, it will point to the tag <table id = "contactList"> irrespective of the level it is on.
8. Using some methods: There are certain methods which are supported by selenium to find the elements using xpaths. Let's see how to use them to create xpath to locate the web elements of a web application.
a) starts-with(): It selects all the web elements which have the value of an attribute starting with a given value. See the html code below:
<table id = "contactList">
<tbody>
<tr>
<td>
<input type="checkbox" id = "contactCheck">
</td>
<td>Mohd Yusuf</td>
<td>India</td>
<td>50000</td>
<td><a href="https://mohdmyyusuf.wixsite.com/testinggeeks/post/selenium-advanced-concepts#">Click</a></td>
</tr>
In the html snippet we can see two tags with id = "contactCheck" and id = "contactList". The attribute id of both the tags is starting with "contact...". So if we write the xpath like //*[starts-with(@id, "contact")], it will select two elements <table id = "contactList"> and <input type="checkbox" id = "contactCheck">. But if we write the xpath like //input[starts-with(@id, "contact")], it will focus only on <input type="checkbox" id = "contactCheck">.
b) text(): This method is used to find an element based on the text displayed on the webpage. It does not check the attributes of the html tag and looks for the \
text to be displayed on web page. See the html code below:
<p id = "myTest">This is to test only</0p>
We can locate this web element in two ways: //*[text()='This is to test only'] OR //p[text()='This is to test only'].
c) Indexing: If multiple tags are selected using a particular xpath and we want to focus on any particular element out of them, we can use the indexing methods.
First way is to append square brackets [] in the end of xpath and put 1, 2 or 3 and so on as per the element you want to focus on, see the xpath below:
//input[@type = 'checkbox']//ancestor::td[1].
If we want to select the last element out of the multiple tags which are selected using a particular xpath, we can use a method last(). To use it append the square bracket
in the end of the xpath and put last into it, see the xpath below:
//input[@type = 'checkbox']//ancestor::td[last()] It will return the last element.
If you want to select second last put last()-1 into the square brackets like //input[@type = 'checkbox']//ancestor::td[last() - 1]
There is another method "position()" to do the indexing. This method can be put into square bracket appended at the end of xpath expression and assign some integer
value to it. See the xpath below:
//input[@type = 'checkbox']//ancestor::td[position() = 2] /* it will select the second td tag on the page*/
9. Some examples to show the use of above methods:
//b[text()='Testing']//parent::h4//following-sibling::ul/liIn the xpath above we are searching <h4> tag from the parent of tag <b>(which contains text as Testing). Then we searched all siblings <ul> tgs of <h4> and then their child <li> tags.
//b[text()='Testing']//ancestor::h4//following-sibling::ul[@class ='menu1']/liWe have done the same thing ie we have searched the all child <li> tags but in different way. This time we searched all <h4> tags which are ancestor/s of the tag <b>. Then Then we searched all siblings <ul> tgs of <h4> and then their child <li> tags.
//div[@class='featured-box cloumnsize1']//descendant::liIn the xpath above we are searching all the descendent <li> tags of the <div> tag.
//*[starts-with(@title, "Software Testing")]//parent::li//following-sibling::liNow we are searching all tags which have text starting with Software Testing. Then all parent <li> tags of it and then the siblings of those <li> tags. We have to pass the @attribute and its value comma separated in the function starts-with().
This article helped me do create dynamic xpath
very clear and crisp content.
Thanks Yusuf for the great article.