zaro

What is XPath in Selenium with an example?

Published in Selenium Locators 6 mins read

XPath, or XML Path, is a powerful language used in Selenium to navigate through the HTML DOM structure and locate specific web elements. It acts as a syntax for finding any element on a web page using an XML path expression, making it an indispensable tool for automating web interactions when other locators fall short.

Understanding XPath

At its core, XPath is a query language for selecting nodes from an XML document. Since HTML documents can be treated as XML documents, XPath provides a flexible way to pinpoint elements on a webpage. It allows you to traverse elements and attributes in the HTML structure, identifying unique elements even when they lack distinct IDs or names.

Why Use XPath in Selenium?

While Selenium offers various locators like ID, Name, Class Name, Tag Name, Link Text, and Partial Link Text, XPath provides unmatched flexibility for several reasons:

  • Locating elements without unique attributes: When an element doesn't have a unique id or name attribute, XPath can locate it based on its position, text content, or other attributes.
  • Navigating complex structures: XPath allows you to move up (parent), down (child), or sideways (sibling) within the DOM, enabling the location of elements relative to others.
  • Handling dynamic elements: It can be used to find elements whose attributes change dynamically, using functions like contains() or starts-with().
  • Verifying text: XPath can select elements based on their visible text content.

Types of XPath

There are two primary types of XPath expressions:

  1. Absolute XPath:

    • Starts from the root node of the HTML document (/html).
    • Provides the full path from the document's beginning to the desired element.
    • Highly fragile: Any minor change in the HTML structure (e.g., adding a new div or moving an element) will break the XPath.
  2. Relative XPath:

    • Starts from anywhere in the HTML document, typically indicated by a double forward slash (//).
    • Locates elements relative to their position, making them more robust than absolute paths.
    • Preferred for automation as they are less prone to breaking due to minor DOM changes.

The following table highlights the key differences:

Feature Absolute XPath Relative XPath
Starting Point /html (root of the DOM) // (anywhere in the DOM)
Robustness Less robust; easily breaks with minor DOM changes More robust; less prone to breakage
Readability Longer and less readable Shorter and more readable
Usage Rarely recommended for automation Highly recommended for automation
Example /html/body/div[1]/form/input[2] //input[@name='username'] or //div/input[2]

Common XPath Syntax and Expressions

XPath expressions typically follow a pattern that includes the tag name, attributes, and their values. Here are some common ways to construct XPath:

  • Basic Syntax: //tagname[@attribute='value']

    • //: Selects nodes from the current node that match the selection no matter where they are in the document.
    • tagname: The HTML tag (e.g., input, div, a).
    • @attribute: The attribute name (e.g., id, name, class, href).
    • 'value': The value of the attribute.
  • Using contains(): //tagname[contains(@attribute, 'partial_value')]

    • Useful when attribute values are dynamic or very long.
  • Using starts-with(): //tagname[starts-with(@attribute, 'start_value')]

    • Locates elements whose attribute value begins with a specific string.
  • Using text(): //tagname[text()='Visible Text']

    • Finds elements based on their visible text content.
  • Using and/or operators:

    • //tagname[@attribute1='value1' and @attribute2='value2']
    • //tagname[@attribute1='value1' or @attribute2='value2']
    • Combines multiple conditions for more precise targeting.
  • By index: //tagname[index]

    • Selects an element based on its position among siblings if multiple elements match (e.g., //input[2] selects the second input element).

Example of XPath in Selenium

Let's consider a simple HTML structure:

<html>
<body>
    <div id="login-form">
        <label>Username:</label>
        <input type="text" name="username" id="user-input" value="yourname">
        <label>Password:</label>
        <input type="password" name="password" class="input-field">
        <button id="submit-btn" class="btn btn-primary">Login</button>
    </div>
    <a href="/forgot-password">Forgot Password?</a>
</body>
</html>

Here's how you would use XPath in Selenium to locate different elements:

Absolute XPath Example (for username input field):

  • /html/body/div[1]/input[1]
    • Note: This is very fragile and not recommended for real-world scenarios.

Relative XPath Examples:

  • By name attribute:
    • To find the "username" input field: //input[@name='username']
  • By id attribute:
    • To find the "username" input field: //input[@id='user-input']
    • To find the "Login" button: //button[@id='submit-btn']
  • Using contains() for class attribute:
    • To find the "password" input field: //input[contains(@class, 'input-field')]
    • To find the "Login" button using partial class: //button[contains(@class, 'btn-primary')]
  • Using text() for the "Login" button:
    • //button[text()='Login']
  • Locating "Forgot Password?" link:
    • //a[text()='Forgot Password?']
    • //a[@href='/forgot-password']

Selenium Python Code Example:

from selenium import webdriver
from selenium.webdriver.common.by import By
import time

# Setup WebDriver (e.g., Chrome)
driver = webdriver.Chrome() # Ensure you have chromedriver installed and in PATH
driver.get("file:///path/to/your/html/file.html") # Replace with the actual path or URL

try:
    # 1. Locate the username input field using relative XPath by name
    username_field = driver.find_element(By.XPATH, "//input[@name='username']")
    username_field.send_keys("testuser")
    print("Found username field and entered text.")

    # 2. Locate the password input field using relative XPath with contains()
    password_field = driver.find_element(By.XPATH, "//input[contains(@class, 'input-field')]")
    password_field.send_keys("securepass")
    print("Found password field and entered text.")

    # 3. Locate the Login button using relative XPath by text()
    login_button = driver.find_element(By.XPATH, "//button[text()='Login']")
    login_button.click()
    print("Clicked the Login button.")

    # 4. Locate the Forgot Password link using relative XPath by href
    forgot_password_link = driver.find_element(By.XPATH, "//a[@href='/forgot-password']")
    print(f"Found link with text: {forgot_password_link.text}")

    time.sleep(2) # Wait to observe action

except Exception as e:
    print(f"An error occurred: {e}")

finally:
    driver.quit()

Note: For the code to run, replace "file:///path/to/your/html/file.html" with the actual path to an HTML file containing the example HTML structure, or a URL to a web page with similar elements.

Best Practices for Using XPath

  • Prefer Relative XPath: Always use relative XPath over absolute XPath for stability.
  • Use Specific Attributes: Target elements using unique attributes like id or name first. If not available, use class or a combination of attributes.
  • Avoid Using Indexes (if possible): While [index] can be useful, if the element's position changes, the XPath will break. Use it as a last resort or when the order is guaranteed to be stable.
  • Test Your XPath: Use browser developer tools (e.g., Chrome DevTools' Elements tab, Ctrl+F) to test your XPath expressions before implementing them in your code.
  • Keep it Concise: Write the shortest and most readable XPath that uniquely identifies the element.

XPath is an incredibly versatile and essential locator strategy in Selenium, providing the means to interact with virtually any element on a web page, regardless of its complexity or the absence of simple identifiers.