XPath in Selenium
XPath stands for XML Path Language. In Selenium WebDriver, XPath is a powerful locator strategy used to identify and interact with web elements in an HTML DOM. XPath can locate elements using attributes, text, relationships between elements, indexes, and different axes.
XPath is especially useful when an element does not have a unique ID, Name, or Class Name, or when the tester needs to create a more flexible locator for dynamic web applications. Selenium WebDriver supports XPath through the By.xpath() method.
XPath is included among the locator strategies covered in Selenium training, along with ID and CSS selectors, and is used for locating web elements in practical browser automation. JustAcademy's Selenium Training Course also covers Selenium WebDriver, locators, web elements, forms, browser interactions, waits, and automation frameworks.
For course demonstration and registration information, visit the Register for Course Demo page.
1. What is XPath?
XPath is a query language used to navigate through elements and attributes in an XML or HTML document. Selenium uses XPath expressions to locate elements in the DOM.
For example, consider:
<input id="username" name="username" type="text">
An XPath locator for this element can be:
//input[@id='username']
Selenium code:
driver.findElement(
By.xpath("//input[@id='username']")
);
2. Why XPath is Important in Selenium
XPath is important because modern web applications often contain complex and dynamic DOM structures. Simple locators may not always be sufficient to identify the required element.
- XPath can locate elements using attributes.
- XPath can locate elements using visible text.
- XPath can locate elements using partial attribute values.
- XPath can navigate parent-child relationships.
- XPath can navigate sibling relationships.
- XPath can locate elements based on surrounding elements.
- XPath can handle many dynamic element scenarios.
- XPath can use indexes when necessary.
- XPath can locate elements inside complex DOM structures.
- XPath is useful when unique IDs or names are unavailable.
3. Basic XPath Syntax
The most common XPath syntax is:
//tagname[@attribute='value']
Example:
//input[@name='username']
Another example:
//button[@type='submit']
4. XPath in Selenium
Selenium uses the By.xpath() method to locate an element.
driver.findElement(
By.xpath("//input[@id='username']")
);
The general structure is:
driver.findElement(By.xpath("XPATH_EXPRESSION"));
5. Required Selenium Imports
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
6. Basic XPath Example
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
public class XPathExample {
public static void main(String[] args) {
WebDriver driver = new ChromeDriver();
driver.manage().window().maximize();
driver.get("https://example.com");
driver.findElement(
By.xpath("//input[@id='username']")
).sendKeys("admin");
driver.quit();
}
}
7. Understanding the DOM
XPath works with the DOM structure of a web page. The browser converts HTML into a tree-like structure containing elements, attributes, text nodes, and relationships.
HTML
|
+-- BODY
|
+-- FORM
|
+-- INPUT
|
+-- INPUT
|
+-- BUTTON
XPath allows Selenium to navigate this structure and identify a specific element.
8. Absolute XPath
An Absolute XPath starts from the root of the HTML document and specifies the complete path to an element.
/html/body/div/form/input
Absolute XPath can become fragile because even a small change in the DOM structure can make the locator invalid.
9. Relative XPath
A Relative XPath usually starts with // and searches for an element based on its characteristics rather than describing the complete path from the root.
//input[@id='username']
Relative XPath is generally easier to maintain because it does not depend on the complete DOM hierarchy.
10. Absolute XPath vs Relative XPath
| Feature | Absolute XPath | Relative XPath |
| Starts with | / | // |
| DOM dependency | High | Lower |
| Maintenance | Can be difficult | Generally easier |
| Flexibility | Limited | High |
| Typical usage | Specific full path | Practical automation locators |
11. XPath Using ID
Suppose the HTML is:
<input id="username" type="text">
XPath:
//input[@id='username']
Selenium:
driver.findElement(
By.xpath("//input[@id='username']")
).sendKeys("admin");
12. XPath Using Name
<input name="email" type="email">
XPath:
//input[@name='email']
Selenium:
driver.findElement(
By.xpath("//input[@name='email']")
).sendKeys("[email protected]");
13. XPath Using Class
<button class="login-button">Login</button>
XPath:
//button[@class='login-button']
14. XPath Using Type Attribute
<input type="password">
XPath:
//input[@type='password']
15. XPath Using Value Attribute
<input type="submit" value="Login">
XPath:
//input[@value='Login']
16. XPath Using Placeholder
<input placeholder="Enter Username" type="text">
XPath:
//input[@placeholder='Enter Username']
17. XPath Using Multiple Attributes
Multiple attributes can be combined using the and operator.
//input[@type='text' and @name='username']
Another example:
//input[@type='text' and @name='username' and @placeholder='Enter Username']
18. XPath Using OR Condition
The or operator can be used when either of multiple conditions can identify the element.
//input[@id='username' or @name='username']
This XPath matches an input whose ID is username or whose name is username.
19. XPath Using Text
The text() function is useful for locating elements based on their exact visible text.
<button>Login</button>
XPath:
//button[text()='Login']
Selenium:
driver.findElement(
By.xpath("//button[text()='Login']")
).click();
20. XPath Using Partial Text with contains()
The contains() function is useful when only part of the text is stable.
<button>Login to Account</button>
XPath:
//button[contains(text(),'Login')]
21. XPath contains() Function
The contains() function can be used with attributes as well as text.
Attribute example:
//input[contains(@id,'user')]
Text example:
//button[contains(text(),'Login')]
Class example:
//div[contains(@class,'container')]
22. XPath starts-with() Function
The starts-with() function identifies elements whose attribute value or text starts with a specified value.
//input[starts-with(@id,'user_')]
This is useful for dynamic IDs such as:
user_12345
user_93842
user_84729
23. XPath normalize-space()
The normalize-space() function removes leading and trailing whitespace and normalizes consecutive whitespace characters.
//button[normalize-space()='Login']
This can be useful when HTML contains unexpected spaces around visible text.
24. normalize-space() with Partial Text
//button[contains(normalize-space(),'Login')]
25. XPath with and
//input[@type='text' and @name='username']
Both conditions must match.
26. XPath with or
//input[@id='username' or @name='username']
At least one condition must match.
27. XPath with not()
The not() function can exclude elements matching a particular condition.
//input[not(@type='hidden')]
This selects input elements that do not have type equal to hidden.
28. XPath Using Multiple Conditions with contains()
//button[contains(@class,'btn') and contains(@class,'login')]
29. XPath Indexing
XPath supports indexes for selecting a particular matching element.
(//input[@type='text'])[1]
Second matching element:
(//input[@type='text'])[2]
30. XPath Indexing Example
<input type="text" name="first">
<input type="text" name="second">
<input type="text" name="third">
First input:
(//input[@type='text'])[1]
Second input:
(//input[@type='text'])[2]
31. XPath Position()
The position() function can be used to identify an element based on its position.
//input[@type='text'][position()=1]
Second element:
//input[@type='text'][position()=2]
32. XPath last()
The last() function identifies the last matching element.
//input[@type='text'][last()]
33. XPath Parent Axis
The parent axis selects the parent of the current element.
//input[@id='username']/parent::div
34. XPath Parent Using ..
The .. notation can be used to move to the parent element.
//input[@id='username']/..
35. XPath Child Axis
The child axis selects child elements.
//div[@id='login']/child::input
Equivalent shorter form:
//div[@id='login']/input
36. XPath Descendant Axis
The descendant axis selects elements located anywhere below the current element.
//div[@id='login']/descendant::input
Shorter form:
//div[@id='login']//input
37. XPath Ancestor Axis
The ancestor axis selects ancestor elements of the current element.
//input[@id='username']/ancestor::form
38. XPath Following-Sibling
The following-sibling axis selects siblings that appear after the current element.
//label[text()='Username']/following-sibling::input
39. XPath Preceding-Sibling
The preceding-sibling axis selects siblings that appear before the current element.
//input[@id='username']/preceding-sibling::label
40. XPath Following Axis
The following axis selects elements appearing later in the document, excluding descendants.
//label[text()='Username']/following::input
41. XPath Preceding Axis
The preceding axis selects elements appearing before the current element.
//input[@id='password']/preceding::label
42. XPath Self Axis
The self axis refers to the current node.
//input[@id='username']/self::input
43. XPath Descendant-or-Self
//div[@id='container']/descendant-or-self::div
44. XPath Ancestor-or-Self
//input[@id='username']/ancestor-or-self::input
45. XPath Axes Reference
| Axis | Purpose |
| ancestor | Selects ancestors |
| ancestor-or-self | Selects ancestors and current node |
| attribute | Selects attributes |
| child | Selects direct children |
| descendant | Selects descendants |
| descendant-or-self | Selects descendants and current node |
| following | Selects nodes later in the document |
| following-sibling | Selects following siblings |
| parent | Selects parent |
| preceding | Selects preceding nodes |
| preceding-sibling | Selects preceding siblings |
| self | Selects current node |
46. XPath Using Parent-Child Relationship
<div class="login-form">
<input name="username">
</div>
XPath:
//div[@class='login-form']/input[@name='username']
47. XPath Using Nested Elements
<div class="container">
<div class="form">
<input name="email">
</div>
</div>
XPath:
//div[@class='container']//input[@name='email']
48. XPath Using Label Relationship
<label>Username</label>
<input type="text" name="username">
XPath:
//label[text()='Username']/following-sibling::input
49. XPath for Form Elements
//form[@id='registration']//input[@name='email']
This identifies an email field within a specific registration form.
50. XPath for Buttons
//button[@type='submit']
Using text:
//button[text()='Submit']
Using partial text:
//button[contains(text(),'Submit')]
51. XPath for Links
//a[@href='/login']
Using text:
//a[text()='Login']
Using partial text:
//a[contains(text(),'Login')]
52. XPath for Checkboxes
//input[@type='checkbox' and @name='terms']
Selenium:
WebElement checkbox = driver.findElement(
By.xpath("//input[@type='checkbox' and @name='terms']")
);
if (!checkbox.isSelected()) {
checkbox.click();
}
53. XPath for Radio Buttons
//input[@type='radio' and @value='male']
Selenium:
driver.findElement(
By.xpath("//input[@type='radio' and @value='male']")
).click();
54. XPath for Dropdown
<select id="country">
<option value="india">India</option>
<option value="usa">USA</option>
</select>
Select element:
//select[@id='country']
India option:
//select[@id='country']/option[@value='india']
55. XPath for Images
<img src="/images/logo.png" alt="Company Logo">
XPath:
//img[@alt='Company Logo']
56. XPath for Tables
<table id="users">
<tr>
<td>John</td>
<td>[email protected]</td>
</tr>
</table>
Table:
//table[@id='users']
Rows:
//table[@id='users']//tr
Cells:
//table[@id='users']//tr//td
57. XPath for Specific Table Row
Suppose a table contains product names:
<table id="products">
<tr>
<td>Laptop</td>
<td>1000</td>
</tr>
<tr>
<td>Phone</td>
<td>700</td>
</tr>
</table>
Row containing Laptop:
//table[@id='products']//tr[td[text()='Laptop']]
58. XPath for Button in Specific Table Row
//table[@id='products']//tr[td[text()='Laptop']]//button
This is useful for actions such as Edit, Delete, View, or Add to Cart for a specific table row.
59. XPath for Dynamic IDs
Suppose an application generates:
<input id="user_847392">
If the stable portion is user_, use:
//input[starts-with(@id,'user_')]
Or:
//input[contains(@id,'user_')]
60. XPath for Dynamic Class
<button class="btn-submit-8392">Submit</button>
XPath:
//button[contains(@class,'btn-submit')]
61. XPath Using Multiple Stable Attributes
//input[contains(@class,'form-control') and @name='email']
Combining stable attributes can reduce the chance of matching the wrong element.
62. XPath for Dynamic Text
Suppose the text is:
Welcome, John
A partial text XPath can be:
//div[contains(text(),'Welcome')]
For whitespace variations:
//div[contains(normalize-space(),'Welcome')]
63. XPath for Text with Extra Spaces
<button> Login </button>
Instead of depending on the exact whitespace:
//button[normalize-space()='Login']
64. XPath for Partial Attribute Value
//input[contains(@placeholder,'Username')]
65. XPath Using Starts-With for URLs
//a[starts-with(@href,'/products')]
This can identify links whose href starts with a known path.
66. XPath for Multiple Matching Elements
When several elements match the same XPath, Selenium's findElement() returns the first matching element according to the WebDriver element search.
driver.findElement(
By.xpath("//button[@class='btn']")
);
If you need all matching elements, use findElements().
67. XPath with findElements()
List<WebElement> buttons = driver.findElements(
By.xpath("//button")
);
68. Count Elements Using XPath
List<WebElement> links = driver.findElements(
By.xpath("//a")
);
System.out.println(
"Number of links: " + links.size()
);
69. Loop Through XPath Results
List<WebElement> links = driver.findElements(
By.xpath("//nav//a")
);
for (WebElement link : links) {
System.out.println(link.getText());
}
70. XPath with Explicit Wait
WebDriverWait wait =
new WebDriverWait(driver, Duration.ofSeconds(10));
WebElement loginButton = wait.until(
ExpectedConditions.elementToBeClickable(
By.xpath("//button[@type='submit']")
)
);
loginButton.click();
71. Required Imports for Explicit Wait
import java.time.Duration;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
72. XPath with Visibility Wait
WebElement dashboard = wait.until(
ExpectedConditions.visibilityOfElementLocated(
By.xpath("//div[@id='dashboard']")
)
);
73. XPath with Presence Wait
WebElement element = wait.until(
ExpectedConditions.presenceOfElementLocated(
By.xpath("//input[@name='username']")
)
);
74. XPath with Clickable Wait
WebElement button = wait.until(
ExpectedConditions.elementToBeClickable(
By.xpath("//button[contains(text(),'Login')]")
)
);
button.click();
75. XPath and Implicit Wait
driver.manage().timeouts().implicitlyWait(
Duration.ofSeconds(10)
);
After configuring the wait, XPath can be used normally with findElement().
76. XPath and Dynamic Web Applications
Dynamic applications may generate changing IDs, classes, text, and DOM structures. XPath functions such as contains(), starts-with(), and normalize-space() can help create more flexible locators.
//input[contains(@id,'user')]
//button[contains(@class,'submit')]
//div[normalize-space()='Login']
77. XPath for Login Form
<form id="loginForm">
<input name="username" type="text">
<input name="password" type="password">
<button type="submit">Login</button>
</form>
Username:
//form[@id='loginForm']//input[@name='username']
Password:
//form[@id='loginForm']//input[@name='password']
Login button:
//form[@id='loginForm']//button[@type='submit']
78. Complete Login Automation Using XPath
driver.findElement(
By.xpath("//input[@name='username']")
).sendKeys("admin");
driver.findElement(
By.xpath("//input[@name='password']")
).sendKeys("admin123");
driver.findElement(
By.xpath("//button[@type='submit']")
).click();
79. XPath for Registration Form
driver.findElement(
By.xpath("//input[@name='firstName']")
).sendKeys("John");
driver.findElement(
By.xpath("//input[@name='lastName']")
).sendKeys("Smith");
driver.findElement(
By.xpath("//input[@type='email']")
).sendKeys("[email protected]");
driver.findElement(
By.xpath("//input[@type='password']")
).sendKeys("Password123");
driver.findElement(
By.xpath("//button[@type='submit']")
).click();
80. XPath for E-Commerce Product
<div class="product-card">
<h3>Laptop</h3>
<button>Add to Cart</button>
</div>
Product:
//div[contains(@class,'product-card')][.//h3[text()='Laptop']]
Add to Cart button for Laptop:
//div[contains(@class,'product-card')][.//h3[text()='Laptop']]//button[contains(text(),'Add to Cart')]
81. XPath for Navigation Links
//nav//a[@href='/courses']
Using text:
//nav//a[normalize-space()='Courses']
82. XPath for Modal
<div id="loginModal" class="modal">
<input name="username">
</div>
Username inside modal:
//div[@id='loginModal']//input[@name='username']
83. XPath for Alert Message
<div class="alert-success">Login successful</div>
XPath:
//div[contains(@class,'alert-success')]
Using text:
//div[contains(text(),'Login successful')]
84. XPath for Error Message
//div[contains(@class,'error-message')]
Or:
//div[contains(normalize-space(),'Invalid password')]
85. XPath for Checkbox State
XPath can locate a checkbox using its attributes. Selenium's isSelected() method is normally used to verify its current state.
WebElement checkbox = driver.findElement(
By.xpath("//input[@type='checkbox' and @name='terms']")
);
if (checkbox.isSelected()) {
System.out.println("Checkbox is selected");
}
86. XPath for Radio Button State
WebElement radio = driver.findElement(
By.xpath("//input[@type='radio' and @value='male']")
);
if (radio.isSelected()) {
System.out.println("Male radio button is selected");
}
87. XPath for Selected Radio Button
For HTML form controls, XPath can sometimes be used with attributes such as @checked, but the presence of the attribute and the current DOM state are not always interchangeable. Selenium's isSelected() method is the preferred way to verify the current selected state.
88. XPath for Disabled Element
//button[@disabled]
Selenium can then verify whether the element is enabled:
WebElement button = driver.findElement(
By.xpath("//button[@disabled]")
);
System.out.println(button.isEnabled());
89. XPath for Required Elements
//input[@required]
90. XPath for Elements with Specific Data Attributes
//button[@data-testid='login-button']
Data attributes can provide stable locator values when they are intentionally designed for automation or testing.
91. XPath with data-testid
<button data-testid="submit-button">Submit</button>
XPath:
//button[@data-testid='submit-button']
92. XPath with aria-label
<button aria-label="Search">🔍</button>
XPath:
//button[@aria-label='Search']
93. XPath for Angular Form Controls
Angular applications may expose attributes such as formcontrolname.
//input[@formcontrolname='email']
94. XPath for React Applications
React applications may contain dynamically generated class names. Stable attributes such as data-testid, aria-label, or application-specific attributes can sometimes provide more maintainable XPath expressions.
//button[@data-testid='login-button']
95. XPath for Specific Table Row
Suppose the table contains:
John
Smith
[email protected]
Active
A row containing the email can be located using:
//table[@id='users']//tr[td[contains(text(),'[email protected]')]]
96. XPath for Action Button in Specific Row
//table[@id='users']//tr[td[contains(text(),'[email protected]')]]//button[contains(text(),'Edit')]
This technique is useful when every row contains similar Edit or Delete buttons.
97. XPath Using Dot for Current Context
The dot . represents the current context node in XPath expressions.
//div[contains(@class,'product')][.//h3[text()='Laptop']]
Here the dot refers to the current product element while checking its descendant heading.
98. XPath Using Descendant Text
//div[.//span[normalize-space()='Laptop']]
This locates a div containing a descendant span with the specified text.
99. XPath with contains() and Multiple Conditions
//div[contains(@class,'product') and .//h3[contains(text(),'Laptop')]]
100. XPath for Nested Buttons
//div[@class='card']//div[@class='actions']//button
101. XPath for Parent Based on Child
Sometimes an element can be identified through a unique child.
//div[.//input[@name='username']]
This selects a div containing the username input.
102. XPath for Ancestor Based on Child
//input[@name='username']/ancestor::form
This locates the form containing the username field.
103. XPath for Sibling-Based Location
//label[normalize-space()='Password']/following-sibling::input
This is useful when the label text is stable but the input does not have a useful unique attribute.
104. XPath with following-sibling and Index
//label[normalize-space()='Username']/following-sibling::input[1]
105. XPath for Elements Based on Parent Attributes
//div[@id='loginForm']//input[@name='username']
This restricts the search to a particular parent container.
106. XPath for Multiple Forms
//form[@id='loginForm']//input[@name='username']
This is safer than using a generic selector such as:
//input[@name='username']
when multiple username fields may exist on the page.
107. XPath with Position in a Parent
//ul[@id='menu']/li[2]
This selects the second direct li child.
108. XPath for First Matching Element
(//button[contains(@class,'submit')])[1]
109. XPath for Last Matching Element
(//button[contains(@class,'submit')])[last()]
110. XPath with not() for Exclusion
//button[not(@disabled)]
This identifies buttons that do not contain a disabled attribute.
111. XPath and findElement()
WebElement username = driver.findElement(
By.xpath("//input[@name='username']")
);
username.sendKeys("admin");
112. XPath and findElements()
List<WebElement> buttons = driver.findElements(
By.xpath("//button")
);
for (WebElement button : buttons) {
System.out.println(button.getText());
}
113. XPath and Page Object Model
XPath locators can be stored inside Page Object classes for better organization and maintainability.
public class LoginPage {
private WebDriver driver;
private By username =
By.xpath("//input[@name='username']");
private By password =
By.xpath("//input[@name='password']");
private By loginButton =
By.xpath("//button[@type='submit']");
public LoginPage(WebDriver driver) {
this.driver = driver;
}
public void login(String user, String pass) {
driver.findElement(username).sendKeys(user);
driver.findElement(password).sendKeys(pass);
driver.findElement(loginButton).click();
}
}
114. Reusable XPath Utility
public WebElement findByXPath(String xpath) {
return driver.findElement(
By.xpath(xpath)
);
}
Usage:
findByXPath("//input[@name='username']")
.sendKeys("admin");
115. Reusable XPath Click Method
public void clickByXPath(String xpath) {
driver.findElement(
By.xpath(xpath)
).click();
}
116. Reusable XPath Type Method
public void typeByXPath(String xpath, String text) {
driver.findElement(
By.xpath(xpath)
).sendKeys(text);
}
117. XPath with TestNG
import org.testng.Assert;
import org.testng.annotations.Test;
@Test
public void verifyLoginButton() {
WebElement button = driver.findElement(
By.xpath("//button[@type='submit']")
);
Assert.assertTrue(button.isDisplayed());
}
118. XPath Validation Example
WebElement message = driver.findElement(
By.xpath("//div[contains(@class,'success-message')]")
);
Assert.assertTrue(message.isDisplayed());
119. XPath and NoSuchElementException
If Selenium cannot find an element using the supplied XPath, NoSuchElementException may occur.
Common reasons include:
- Incorrect XPath syntax.
- Wrong attribute value.
- Element is not present.
- Element has not loaded yet.
- Wrong iframe context.
- Incorrect page or URL.
- DOM changed after navigation.
120. XPath and InvalidSelectorException
If the XPath expression is syntactically invalid, Selenium may throw an InvalidSelectorException.
Example of a valid XPath:
//input[@id='username']
Always verify complex XPath expressions in browser developer tools before adding them to automation code.
121. XPath and StaleElementReferenceException
A previously located element can become stale if the page refreshes or the DOM element is replaced.
A common solution is to locate the element again rather than continuing to use an outdated WebElement reference.
122. XPath and ElementClickInterceptedException
If another element overlays the target, Selenium may not be able to click it even when the XPath is correct.
Possible solutions include:
- Wait for the overlay to disappear.
- Wait until the target becomes clickable.
- Scroll appropriately.
- Handle popups or modal windows.
123. XPath with iframe
If an element is inside an iframe, Selenium must first switch into the iframe.
driver.switchTo().frame("loginFrame");
driver.findElement(
By.xpath("//input[@name='username']")
).sendKeys("admin");
driver.switchTo().defaultContent();
124. XPath with Nested iframe
driver.switchTo().frame("outerFrame");
driver.switchTo().frame("innerFrame");
driver.findElement(
By.xpath("//input[@id='username']")
).sendKeys("admin");
driver.switchTo().defaultContent();
125. XPath and Shadow DOM
XPath does not automatically cross a Shadow DOM boundary. If the target element exists inside a shadow root, Selenium must first access the shadow root and then locate the element within that context using supported Shadow DOM APIs.
126. XPath and SVG Elements
SVG elements can require special attention because their namespace and DOM structure can differ from ordinary HTML elements.
For example:
//*[name()='svg']
For a specific SVG element, inspect the actual DOM structure and create a locator based on stable attributes.
127. XPath vs CSS Selector
| Feature | XPath | CSS Selector |
| Method | By.xpath() | By.cssSelector() |
| ID matching | Supported | Supported |
| Class matching | Supported | Supported |
| Attribute matching | Supported | Supported |
| Text matching | Strong | More limited |
| Parent navigation | Strong | Different model |
| Sibling navigation | Strong | Supported |
| Complex DOM relationships | Highly expressive | Expressive but different |
| Partial attribute matching | contains(), starts-with() | *, ^=, $= |
128. XPath vs ID Locator
| Feature | ID | XPath |
| Method | By.id() | By.xpath() |
| Syntax | Simple | More expressive |
| Attributes | ID only | Multiple attributes |
| Relationships | No | Yes |
| Text | No | Yes |
129. XPath Best Practices
- Prefer relative XPath over unnecessarily long absolute XPath.
- Use stable attributes whenever possible.
- Prefer unique and meaningful attributes.
- Use
data-testid or similar test attributes when intentionally provided by the application.
- Use
contains() for stable portions of dynamic attributes.
- Use
starts-with() when the beginning of an attribute is stable.
- Use
normalize-space() when whitespace can vary.
- Avoid unnecessary indexes.
- Avoid very long DOM paths.
- Avoid depending on dynamically generated values unless there is a stable pattern.
- Use explicit waits for dynamically loaded elements.
- Store XPath locators in Page Object classes.
- Validate complex XPath expressions before using them in tests.
130. Avoid Fragile Absolute XPath
Avoid locators such as:
/html/body/div[2]/div[1]/form/div[3]/input
A more maintainable locator may be:
//form[@id='loginForm']//input[@name='username']
131. Avoid Unnecessary Indexes
Instead of:
(//button)[7]
Prefer a stable locator:
//button[@type='submit' and normalize-space()='Login']
Indexes can be useful when the DOM genuinely requires positional selection, but they should not be the first choice when a stable attribute is available.
132. Validate XPath in Browser Developer Tools
Browsers provide developer tools that can be used to inspect the DOM and test XPath expressions.
Open Web Page
↓
Right Click Element
↓
Select Inspect
↓
Understand DOM Structure
↓
Identify Stable Attributes
↓
Create XPath
↓
Test XPath
↓
Use XPath in Selenium
↓
Validate Automation
133. Testing XPath in Browser Console
XPath can be tested in browser developer tools using document.evaluate().
document.evaluate(
"//input[@id='username']",
document,
null,
XPathResult.FIRST_ORDERED_NODE_TYPE,
null
).singleNodeValue;
This helps verify whether an XPath identifies the intended element before implementing it in Selenium.
134. Practical Project: Login Automation
driver.get("https://example.com/login");
driver.findElement(
By.xpath("//input[@name='username']")
).sendKeys("admin");
driver.findElement(
By.xpath("//input[@name='password']")
).sendKeys("admin123");
driver.findElement(
By.xpath("//button[@type='submit']")
).click();
135. Practical Project: Registration Automation
driver.findElement(
By.xpath("//input[@name='firstName']")
).sendKeys("John");
driver.findElement(
By.xpath("//input[@name='lastName']")
).sendKeys("Smith");
driver.findElement(
By.xpath("//input[@name='email']")
).sendKeys("[email protected]");
driver.findElement(
By.xpath("//input[@name='password']")
).sendKeys("Password123");
driver.findElement(
By.xpath("//button[contains(normalize-space(),'Register')]")
).click();
136. Practical Project: E-Commerce Product Selection
driver.findElement(
By.xpath("//h3[normalize-space()='Laptop']")
);
driver.findElement(
By.xpath("//div[contains(@class,'product-card')][.//h3[normalize-space()='Laptop']]//button[contains(normalize-space(),'Add to Cart')]")
).click();
137. Practical Project: Table Data Extraction
List<WebElement> rows = driver.findElements(
By.xpath("//table[@id='users']//tbody//tr")
);
for (WebElement row : rows) {
System.out.println(row.getText());
}
138. Practical Project: Table Row Action
WebElement editButton = driver.findElement(
By.xpath(
"//table[@id='users']//tr[td[normalize-space()='[email protected]']]//button[contains(normalize-space(),'Edit')]"
)
);
editButton.click();
139. Practical Project: Navigation Automation
driver.findElement(
By.xpath("//nav//a[normalize-space()='Courses']")
).click();
140. Practical Project: Checkbox Selection
WebElement terms = driver.findElement(
By.xpath("//input[@type='checkbox' and @name='terms']")
);
if (!terms.isSelected()) {
terms.click();
}
141. Practical Project: Radio Button Selection
WebElement male = driver.findElement(
By.xpath("//input[@type='radio' and @value='male']")
);
if (!male.isSelected()) {
male.click();
}
142. Practical Project: Dropdown Option
driver.findElement(
By.xpath("//select[@id='country']")
);
driver.findElement(
By.xpath("//select[@id='country']/option[@value='india']")
).click();
143. XPath Automation Flow
Launch Browser
↓
Open Application
↓
Inspect DOM
↓
Identify Stable Attributes
↓
Create XPath
↓
Validate XPath
↓
Use By.xpath()
↓
Locate WebElement
↓
Perform Action
↓
Validate Result
↓
Continue Test
↓
Close Browser
144. XPath Quick Reference
| Requirement | XPath |
| ID | //input[@id='username'] |
| Name | //input[@name='username'] |
| Class | //button[@class='login-button'] |
| Attribute | //input[@type='text'] |
| Multiple Attributes | //input[@type='text' and @name='username'] |
| Exact Text | //button[text()='Login'] |
| Partial Text | //button[contains(text(),'Login')] |
| Contains Attribute | //input[contains(@id,'user')] |
| Starts With | //input[starts-with(@id,'user_')] |
| Normalized Text | //button[normalize-space()='Login'] |
| Parent | //input[@id='username']/parent::div |
| Child | //div[@id='login']/child::input |
| Descendant | //div[@id='login']//input |
| Ancestor | //input[@id='username']/ancestor::form |
| Following Sibling | //label/following-sibling::input |
| Preceding Sibling | //input/preceding-sibling::label |
| First Match | (//button)[1] |
| Last Match | (//button)[last()] |
| Not | //input[not(@type='hidden')] |
145. XPath Interview Questions
Q1. What is XPath?
XPath is a language used to navigate XML and HTML DOM structures and identify specific nodes. Selenium uses XPath expressions to locate web elements.
Q2. What is the difference between absolute and relative XPath?
Absolute XPath starts from the root and describes the complete path, while relative XPath generally starts with // and identifies elements using attributes, text, relationships, or other conditions.
Q3. Which Selenium method is used for XPath?
By.xpath()
Q4. How do you locate an element by ID using XPath?
driver.findElement(
By.xpath("//input[@id='username']")
);
Q5. How do you locate an element using text?
driver.findElement(
By.xpath("//button[text()='Login']")
);
Q6. How do you locate an element using partial text?
driver.findElement(
By.xpath("//button[contains(text(),'Login')]")
);
Q7. What is contains() used for?
contains() is used to match a substring within an attribute value or text.
Q8. What is starts-with() used for?
starts-with() identifies elements whose selected attribute or text starts with a specified value.
Q9. What is normalize-space()?
It normalizes whitespace and is useful when text contains unwanted leading, trailing, or repeated spaces.
Q10. How do you select a parent element?
//input[@id='username']/parent::div
Q11. How do you select a child element?
//div[@id='login']/child::input
Q12. How do you select a sibling?
//label/following-sibling::input
Q13. How do you select the last matching element?
(//button)[last()]
Q14. How do you handle dynamic IDs?
//input[starts-with(@id,'user_')]
Q15. Can XPath be used with findElements()?
Yes.
driver.findElements(
By.xpath("//button")
);
Q16. Can XPath locate elements based on visible text?
Yes. Functions such as text() and normalize-space() can be used.
Q17. What is the difference between // and /?
A single slash is used for a direct path step, while // is commonly used to search through descendants from the current context or document.
Q18. Can XPath work with dynamic web pages?
Yes. Functions such as contains(), starts-with(), and stable attribute combinations can help identify dynamic elements.
Q19. Can XPath cross an iframe?
No. Selenium must first switch into the iframe context before locating elements inside it.
Q20. Can XPath automatically cross Shadow DOM boundaries?
No. The appropriate shadow root context must be accessed before locating elements inside it.
146. XPath Best-Practice Checklist
- Use relative XPath where appropriate.
- Prefer stable attributes.
- Use unique identifiers whenever available.
- Use multiple attributes when necessary.
- Use text-based XPath when visible text is stable.
- Use
contains() for stable partial values.
- Use
starts-with() for predictable dynamic prefixes.
- Use
normalize-space() when whitespace varies.
- Avoid unnecessary indexes.
- Avoid long absolute XPath expressions.
- Avoid dynamically generated values when a stable attribute is available.
- Use explicit waits for dynamic elements.
- Switch into iframes before locating elements inside them.
- Handle Shadow DOM through its proper context.
- Keep XPath locators inside Page Object classes.
- Test XPath expressions before using them in large automation suites.
147. Final Conclusion
XPath is one of the most powerful locator strategies available in Selenium WebDriver. It allows automation testers to identify elements using IDs, names, classes, attributes, visible text, partial values, indexes, parent-child relationships, sibling relationships, and advanced XPath axes.
A maintainable XPath should generally rely on stable attributes and meaningful relationships rather than fragile absolute DOM paths or unnecessary indexes. Functions such as contains(), starts-with(), and normalize-space() are especially useful when working with dynamic web applications.
XPath becomes even more useful when combined with Selenium concepts such as WebElement methods, explicit waits, Page Object Model, TestNG, dynamic element handling, frames, forms, tables, and real-world automation projects.
For structured learning of Selenium WebDriver, XPath, CSS Selectors, Web Elements, browser automation, waits, TestNG, Page Object Model, and practical automation testing, explore the JustAcademy's Selenium Training Course.
To explore the available course demonstration and registration options, visit the Register for Course Demo page.