26

How to Handle Dynamic Changing IDs In XPath? for example :

//div[@id='post-body-3647323225296998740']/div[1]/form[1]/input[1]

In this xpath id "3647323225296998740" is changing every time when reloading the page.

Is there any way to handle this type of situation in Selenium?

2
  • How to Handle Dynamic Changing IDs? for example , ID is "ss2j7z0k3x5r4y6g1rSROMLLUG65N65Z75U72R61G6eG6dP73Y" Commented Jul 21, 2017 at 5:07
  • 1
    Actually dynamic IDs appearing on pages are a code smell that you should be querying. Particularly addressing the question, 'is it leaking information about the internals of the system?' In general dynamic ID should be avoided. Further more, if automated testing is non-functional requirement of the project, suitable ID should be provided as per a proper locator strategy. Commented Oct 11, 2018 at 16:43

6 Answers 6

21

At this situation, We have lots of options-

Option 1: Look for any other attribute which Is not changing every time In that div node like name, class etc. So If this div node has class attribute then we can write xpath as bellow.

//div[@class='post-body entry-content']/div[1]/form[1]/input[1] 

Option 2: We can use absolute xpath (full xpath) where you do not need to give any attribute names In xpath.

/html/body/div[3]/div[2]/div[2]/div[2]/div[2]/div[2]/div[2]/div/div[4]/div[1]/div/div/div/div[1]/div/div/div/div[1]/div[2]/div[1]/form[1]/input[1] 

Option 3: We can use starts-with function. In this xpath's ID attribute, "post-body-" part remains same every time.

 //div[starts-with(@id,'post-body-')]/div[1]/form[1]/input[1] 

Option 4: We can use contains function. Same way you can use contains function as bellow.

 div[contains(@id,'post-body-')]/div[1]/form[1]/input[1]
3
  • 2
    Imho, option 2 is not recommended, it is too brittle
    – olyv
    Commented Nov 28, 2016 at 6:16
  • Yes, maximum time we avoids to use Absolute x-path, but sometimes relative xpath is not working while locating the element, in that case we have to use absolute xpath: in which we have to design absolute path from starting node to descent element node.
    – Bharat Mane
    Commented Dec 22, 2016 at 9:05
  • 1
    Also, don't forget that you can check multiple parts of an id: constant1-12232-constant2: "//*[contains(@id,'constant1') and contains(@id,'constant2)]"
    – tjb
    Commented May 3, 2019 at 9:13
12

Use contains() or starts-with() function in XPath:

Solution:

With contains():

//div[contains(@id,'post-body')]/div[1]/form[1]/input[1]

With starts-with():

//div[starts-with(@id,'post-body')]/div[1]/form[1]/input[1]
0
9

Use other elements and attributes for partial and combination matches

Generally in these cases of database backed and changing ID's in web element selectors your options are to look for one or more of:

  • a higher level selector such as the form name, e.g. //form/input[@type='submit']
  • a combo of non-unique selectors that together are unique e.g. //form[@class='new_user']/input[@type='submit']
  • a data attribute such as form[@data-form='new-user']//input
  • a partial match using starts-with or contains against post-body- e.g.
    //div[starts-with(@id,'post-body-')]/div[1]/form[1]/input[1]
1

If the id is changing dynamically for a particular xpath then we can use the below xpath functions:

  1. contains :xpath Syntax: //html tag[contains(text()/@attribute, 'Expected Value')]

  2. Following-Siblings:

    Xpath Syntax : //html tag/following-siblings::html tag ex: //img[@src = 'image2.jpg']/following-siblings::input[@type = 'button']

  3. Preceding-Siblings: syntax will be same as following-Siblings

  4. The descendant function which is used to identify the grand child node by skipping all

sub, node from the current HTML tag.

1
  • 1
    I don't think "Siblings" will work in this situation.
    – Bharat Mane
    Commented May 4, 2016 at 6:05
1

The id attribute of the <div> tag is dynamic which will change each time the webpage is accessed. In these cases you need to construct dynamic locator strategies as follows:

  • //div[starts-with(@id, 'post-body-')]/div/form/input
    

Note: The second <div> is the first/only child of it's parent, the <form> is the first/only child of it's parent, the <input> is the first/only child of it's parent, so you don't require the indexes.

PS: However a more optimized way would have been to construct the locator strategies based on the attributes of the <input> tag only.

0

You can use regex in this case, Instead of using XPath you can use some wild cards in CSS Selector to locate the same. Please refer this link.

input[id^='post-body-'][id$='id pattern']

Refer this link for knowing how to use CSS selectors using wildcards.

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