XPath Advanced Techniques
Master advanced XPath patterns for complex element location scenarios.
Selenium 3 & 4 Medium
This guide covers advanced XPath techniques for handling complex scenarios that simpler locators can’t address.
Boolean Operators
Combine conditions using and, or, and not():
Boolean Logic in XPath
Selenium 3 & 4 Stable
// AND - both conditions must be trueWebElement textInput = driver.findElement( By.xpath("//input[@type='text' and @name='username']"));
// OR - either conditionWebElement anyButton = driver.findElement( By.xpath("//button[@type='submit' or @type='button']"));
// NOT - exclude elementsWebElement enabledInput = driver.findElement( By.xpath("//input[not(@disabled)]"));
// Complex combinationWebElement specific = driver.findElement(By.xpath( "//input[@type='text' and not(@readonly) and (contains(@class, 'form') or @name='search')]"));
// Find visible elements (not hidden)WebElement visible = driver.findElement( By.xpath("//div[not(contains(@style, 'display: none'))]"));# AND - both conditions must be truetext_input = driver.find_element( By.XPATH, "//input[@type='text' and @name='username']")
# OR - either conditionany_button = driver.find_element( By.XPATH, "//button[@type='submit' or @type='button']")
# NOT - exclude elementsenabled_input = driver.find_element( By.XPATH, "//input[not(@disabled)]")
# Complex combinationspecific = driver.find_element(By.XPATH, "//input[@type='text' and not(@readonly) and (contains(@class, 'form') or @name='search')]")
# Find visible elements (not hidden)visible = driver.find_element( By.XPATH, "//div[not(contains(@style, 'display: none'))]")// AND - both conditions must be trueconst textInput = await driver.findElement( By.xpath("//input[@type='text' and @name='username']"));
// OR - either conditionconst anyButton = await driver.findElement( By.xpath("//button[@type='submit' or @type='button']"));
// NOT - exclude elementsconst enabledInput = await driver.findElement( By.xpath("//input[not(@disabled)]"));
// Complex combinationconst specific = await driver.findElement(By.xpath( "//input[@type='text' and not(@readonly) and (contains(@class, 'form') or @name='search')]"));
// Find visible elements (not hidden)const visible = await driver.findElement( By.xpath("//div[not(contains(@style, 'display: none'))]"));// AND - both conditions must be trueIWebElement textInput = driver.FindElement( By.XPath("//input[@type='text' and @name='username']"));
// OR - either conditionIWebElement anyButton = driver.FindElement( By.XPath("//button[@type='submit' or @type='button']"));
// NOT - exclude elementsIWebElement enabledInput = driver.FindElement( By.XPath("//input[not(@disabled)]"));
// Complex combinationIWebElement specific = driver.FindElement(By.XPath( "//input[@type='text' and not(@readonly) and (contains(@class, 'form') or @name='search')]"));
// Find visible elements (not hidden)IWebElement visible = driver.FindElement( By.XPath("//div[not(contains(@style, 'display: none'))]"));Axes Navigation
XPath axes provide powerful navigation through the DOM:
XPath Axes
Selenium 3 & 4 Medium
// ancestor - all ancestors up to rootWebElement form = driver.findElement( By.xpath("//input[@id='email']/ancestor::form"));
// ancestor-or-self - includes current elementWebElement formOrSelf = driver.findElement( By.xpath("//form[@id='login']/ancestor-or-self::*[@class='container']"));
// descendant - all children at any depthList<WebElement> allInputs = driver.findElements( By.xpath("//form[@id='login']/descendant::input"));
// following - everything after in document orderWebElement nextSection = driver.findElement( By.xpath("//h2[text()='Section 1']/following::h2"));
// following-sibling - siblings after currentList<WebElement> laterItems = driver.findElements( By.xpath("//li[@class='active']/following-sibling::li"));
// preceding - everything before in document orderWebElement prevSection = driver.findElement( By.xpath("//h2[text()='Section 2']/preceding::h2"));
// preceding-sibling - siblings before currentWebElement labelBefore = driver.findElement( By.xpath("//input[@id='email']/preceding-sibling::label"));# ancestor - all ancestors up to rootform = driver.find_element( By.XPATH, "//input[@id='email']/ancestor::form")
# ancestor-or-self - includes current elementform_or_self = driver.find_element( By.XPATH, "//form[@id='login']/ancestor-or-self::*[@class='container']")
# descendant - all children at any depthall_inputs = driver.find_elements( By.XPATH, "//form[@id='login']/descendant::input")
# following - everything after in document ordernext_section = driver.find_element( By.XPATH, "//h2[text()='Section 1']/following::h2")
# following-sibling - siblings after currentlater_items = driver.find_elements( By.XPATH, "//li[@class='active']/following-sibling::li")
# preceding - everything before in document orderprev_section = driver.find_element( By.XPATH, "//h2[text()='Section 2']/preceding::h2")
# preceding-sibling - siblings before currentlabel_before = driver.find_element( By.XPATH, "//input[@id='email']/preceding-sibling::label")// ancestor - all ancestors up to rootconst form = await driver.findElement( By.xpath("//input[@id='email']/ancestor::form"));
// ancestor-or-self - includes current elementconst formOrSelf = await driver.findElement( By.xpath("//form[@id='login']/ancestor-or-self::*[@class='container']"));
// descendant - all children at any depthconst allInputs = await driver.findElements( By.xpath("//form[@id='login']/descendant::input"));
// following - everything after in document orderconst nextSection = await driver.findElement( By.xpath("//h2[text()='Section 1']/following::h2"));
// following-sibling - siblings after currentconst laterItems = await driver.findElements( By.xpath("//li[@class='active']/following-sibling::li"));
// preceding - everything before in document orderconst prevSection = await driver.findElement( By.xpath("//h2[text()='Section 2']/preceding::h2"));
// preceding-sibling - siblings before currentconst labelBefore = await driver.findElement( By.xpath("//input[@id='email']/preceding-sibling::label"));// ancestor - all ancestors up to rootIWebElement form = driver.FindElement( By.XPath("//input[@id='email']/ancestor::form"));
// ancestor-or-self - includes current elementIWebElement formOrSelf = driver.FindElement( By.XPath("//form[@id='login']/ancestor-or-self::*[@class='container']"));
// descendant - all children at any depthIList<IWebElement> allInputs = driver.FindElements( By.XPath("//form[@id='login']/descendant::input"));
// following - everything after in document orderIWebElement nextSection = driver.FindElement( By.XPath("//h2[text()='Section 1']/following::h2"));
// following-sibling - siblings after currentIList<IWebElement> laterItems = driver.FindElements( By.XPath("//li[@class='active']/following-sibling::li"));
// preceding - everything before in document orderIWebElement prevSection = driver.FindElement( By.XPath("//h2[text()='Section 2']/preceding::h2"));
// preceding-sibling - siblings before currentIWebElement labelBefore = driver.FindElement( By.XPath("//input[@id='email']/preceding-sibling::label"));Working with Tables
XPath is excellent for table navigation:
Table Navigation with XPath
Selenium 3 & 4 Medium
// Find cell by row and column indexWebElement cell = driver.findElement( By.xpath("//table[@id='data']//tr[3]/td[2]"));
// Find row containing specific textWebElement row = driver.findElement( By.xpath("//table[@id='data']//tr[td[contains(text(), 'John')]]"));
// Get all cells in a column (e.g., 3rd column)List<WebElement> column = driver.findElements( By.xpath("//table[@id='data']//tr/td[3]"));
// Find cell relative to header// First, find which column index "Price" is in, then get dataWebElement priceHeader = driver.findElement( By.xpath("//table[@id='data']//th[text()='Price']"));// Count preceding siblings + 1 to get column positionint colIndex = driver.findElements( By.xpath("//table[@id='data']//th[text()='Price']/preceding-sibling::th")).size() + 1;WebElement firstPrice = driver.findElement( By.xpath("//table[@id='data']//tbody/tr[1]/td[" + colIndex + "]"));
// Find action button in row with specific valueWebElement editBtn = driver.findElement(By.xpath( "//table//tr[td[text()='Product A']]//button[text()='Edit']"));# Find cell by row and column indexcell = driver.find_element( By.XPATH, "//table[@id='data']//tr[3]/td[2]")
# Find row containing specific textrow = driver.find_element( By.XPATH, "//table[@id='data']//tr[td[contains(text(), 'John')]]")
# Get all cells in a column (e.g., 3rd column)column = driver.find_elements( By.XPATH, "//table[@id='data']//tr/td[3]")
# Find cell relative to headerprice_header = driver.find_element( By.XPATH, "//table[@id='data']//th[text()='Price']")# Count preceding siblings + 1 to get column positioncol_index = len(driver.find_elements( By.XPATH, "//table[@id='data']//th[text()='Price']/preceding-sibling::th")) + 1first_price = driver.find_element( By.XPATH, f"//table[@id='data']//tbody/tr[1]/td[{col_index}]")
# Find action button in row with specific valueedit_btn = driver.find_element(By.XPATH, "//table//tr[td[text()='Product A']]//button[text()='Edit']")// Find cell by row and column indexconst cell = await driver.findElement( By.xpath("//table[@id='data']//tr[3]/td[2]"));
// Find row containing specific textconst row = await driver.findElement( By.xpath("//table[@id='data']//tr[td[contains(text(), 'John')]]"));
// Get all cells in a column (e.g., 3rd column)const column = await driver.findElements( By.xpath("//table[@id='data']//tr/td[3]"));
// Find cell relative to headerconst priceHeader = await driver.findElement( By.xpath("//table[@id='data']//th[text()='Price']"));const precedingSiblings = await driver.findElements( By.xpath("//table[@id='data']//th[text()='Price']/preceding-sibling::th"));const colIndex = precedingSiblings.length + 1;const firstPrice = await driver.findElement( By.xpath(`//table[@id='data']//tbody/tr[1]/td[${colIndex}]`));
// Find action button in row with specific valueconst editBtn = await driver.findElement(By.xpath( "//table//tr[td[text()='Product A']]//button[text()='Edit']"));// Find cell by row and column indexIWebElement cell = driver.FindElement( By.XPath("//table[@id='data']//tr[3]/td[2]"));
// Find row containing specific textIWebElement row = driver.FindElement( By.XPath("//table[@id='data']//tr[td[contains(text(), 'John')]]"));
// Get all cells in a column (e.g., 3rd column)IList<IWebElement> column = driver.FindElements( By.XPath("//table[@id='data']//tr/td[3]"));
// Find cell relative to headerIWebElement priceHeader = driver.FindElement( By.XPath("//table[@id='data']//th[text()='Price']"));int colIndex = driver.FindElements( By.XPath("//table[@id='data']//th[text()='Price']/preceding-sibling::th")).Count + 1;IWebElement firstPrice = driver.FindElement( By.XPath($"//table[@id='data']//tbody/tr[1]/td[{colIndex}]"));
// Find action button in row with specific valueIWebElement editBtn = driver.FindElement(By.XPath( "//table//tr[td[text()='Product A']]//button[text()='Edit']"));Dynamic Elements
Handle elements with dynamic or partial attributes:
Handling Dynamic Attributes
Selenium 3 & 4 Medium
// ID starts with static prefixWebElement dynamicId = driver.findElement( By.xpath("//*[starts-with(@id, 'user_')]"));
// ID ends with pattern (no built-in ends-with in XPath 1.0)WebElement endsWithId = driver.findElement(By.xpath( "//*[substring(@id, string-length(@id) - 5) = '_field']"));
// Class contains valueWebElement partialClass = driver.findElement( By.xpath("//*[contains(@class, 'active')]"));
// Multiple partial matchesWebElement complex = driver.findElement(By.xpath( "//*[contains(@class, 'btn') and contains(@class, 'primary')]"));
// Match any attribute valueWebElement anyAttr = driver.findElement( By.xpath("//*[@*='submit-button']"));
// Attribute exists (any value)WebElement hasAttr = driver.findElement( By.xpath("//input[@placeholder]"));# ID starts with static prefixdynamic_id = driver.find_element( By.XPATH, "//*[starts-with(@id, 'user_')]")
# ID ends with pattern (no built-in ends-with in XPath 1.0)ends_with_id = driver.find_element(By.XPATH, "//*[substring(@id, string-length(@id) - 5) = '_field']")
# Class contains valuepartial_class = driver.find_element( By.XPATH, "//*[contains(@class, 'active')]")
# Multiple partial matchescomplex = driver.find_element(By.XPATH, "//*[contains(@class, 'btn') and contains(@class, 'primary')]")
# Match any attribute valueany_attr = driver.find_element( By.XPATH, "//*[@*='submit-button']")
# Attribute exists (any value)has_attr = driver.find_element( By.XPATH, "//input[@placeholder]")// ID starts with static prefixconst dynamicId = await driver.findElement( By.xpath("//*[starts-with(@id, 'user_')]"));
// ID ends with pattern (no built-in ends-with in XPath 1.0)const endsWithId = await driver.findElement(By.xpath( "//*[substring(@id, string-length(@id) - 5) = '_field']"));
// Class contains valueconst partialClass = await driver.findElement( By.xpath("//*[contains(@class, 'active')]"));
// Multiple partial matchesconst complex = await driver.findElement(By.xpath( "//*[contains(@class, 'btn') and contains(@class, 'primary')]"));
// Match any attribute valueconst anyAttr = await driver.findElement( By.xpath("//*[@*='submit-button']"));
// Attribute exists (any value)const hasAttr = await driver.findElement( By.xpath("//input[@placeholder]"));// ID starts with static prefixIWebElement dynamicId = driver.FindElement( By.XPath("//*[starts-with(@id, 'user_')]"));
// ID ends with pattern (no built-in ends-with in XPath 1.0)IWebElement endsWithId = driver.FindElement(By.XPath( "//*[substring(@id, string-length(@id) - 5) = '_field']"));
// Class contains valueIWebElement partialClass = driver.FindElement( By.XPath("//*[contains(@class, 'active')]"));
// Multiple partial matchesIWebElement complex = driver.FindElement(By.XPath( "//*[contains(@class, 'btn') and contains(@class, 'primary')]"));
// Match any attribute valueIWebElement anyAttr = driver.FindElement( By.XPath("//*[@*='submit-button']"));
// Attribute exists (any value)IWebElement hasAttr = driver.FindElement( By.XPath("//input[@placeholder]"));Real-World Patterns
Common XPath patterns for typical scenarios:
Common XPath Patterns
Selenium 3 & 4 Medium
// Find input by its label textWebElement inputByLabel = driver.findElement( By.xpath("//label[text()='Email']/following-sibling::input"));
// Alternative: label with 'for' attributeWebElement inputByFor = driver.findElement(By.xpath( "//input[@id=//label[text()='Email']/@for]"));
// Find error message for specific fieldWebElement errorMsg = driver.findElement(By.xpath( "//input[@name='email']/following-sibling::span[@class='error']"));
// Find dropdown option by visible textWebElement option = driver.findElement(By.xpath( "//select[@name='country']/option[text()='United States']"));
// Find card/item by title and click its buttonWebElement cardButton = driver.findElement(By.xpath( "//div[contains(@class, 'card')][.//h3[text()='Premium Plan']]//button"));
// Find nth matching element globallyWebElement thirdResult = driver.findElement( By.xpath("(//div[@class='search-result'])[3]"));
// Modal/dialog that's currently visibleWebElement modal = driver.findElement(By.xpath( "//div[contains(@class, 'modal')][not(contains(@class, 'hidden'))]"));# Find input by its label textinput_by_label = driver.find_element( By.XPATH, "//label[text()='Email']/following-sibling::input")
# Alternative: label with 'for' attributeinput_by_for = driver.find_element(By.XPATH, "//input[@id=//label[text()='Email']/@for]")
# Find error message for specific fielderror_msg = driver.find_element(By.XPATH, "//input[@name='email']/following-sibling::span[@class='error']")
# Find dropdown option by visible textoption = driver.find_element(By.XPATH, "//select[@name='country']/option[text()='United States']")
# Find card/item by title and click its buttoncard_button = driver.find_element(By.XPATH, "//div[contains(@class, 'card')][.//h3[text()='Premium Plan']]//button")
# Find nth matching element globallythird_result = driver.find_element( By.XPATH, "(//div[@class='search-result'])[3]")
# Modal/dialog that's currently visiblemodal = driver.find_element(By.XPATH, "//div[contains(@class, 'modal')][not(contains(@class, 'hidden'))]")// Find input by its label textconst inputByLabel = await driver.findElement( By.xpath("//label[text()='Email']/following-sibling::input"));
// Alternative: label with 'for' attributeconst inputByFor = await driver.findElement(By.xpath( "//input[@id=//label[text()='Email']/@for]"));
// Find error message for specific fieldconst errorMsg = await driver.findElement(By.xpath( "//input[@name='email']/following-sibling::span[@class='error']"));
// Find dropdown option by visible textconst option = await driver.findElement(By.xpath( "//select[@name='country']/option[text()='United States']"));
// Find card/item by title and click its buttonconst cardButton = await driver.findElement(By.xpath( "//div[contains(@class, 'card')][.//h3[text()='Premium Plan']]//button"));
// Find nth matching element globallyconst thirdResult = await driver.findElement( By.xpath("(//div[@class='search-result'])[3]"));
// Modal/dialog that's currently visibleconst modal = await driver.findElement(By.xpath( "//div[contains(@class, 'modal')][not(contains(@class, 'hidden'))]"));// Find input by its label textIWebElement inputByLabel = driver.FindElement( By.XPath("//label[text()='Email']/following-sibling::input"));
// Alternative: label with 'for' attributeIWebElement inputByFor = driver.FindElement(By.XPath( "//input[@id=//label[text()='Email']/@for]"));
// Find error message for specific fieldIWebElement errorMsg = driver.FindElement(By.XPath( "//input[@name='email']/following-sibling::span[@class='error']"));
// Find dropdown option by visible textIWebElement option = driver.FindElement(By.XPath( "//select[@name='country']/option[text()='United States']"));
// Find card/item by title and click its buttonIWebElement cardButton = driver.FindElement(By.XPath( "//div[contains(@class, 'card')][.//h3[text()='Premium Plan']]//button"));
// Find nth matching element globallyIWebElement thirdResult = driver.FindElement( By.XPath("(//div[@class='search-result'])[3]"));
// Modal/dialog that's currently visibleIWebElement modal = driver.FindElement(By.XPath( "//div[contains(@class, 'modal')][not(contains(@class, 'hidden'))]"));XPath Debugging Tips
- Test in browser DevTools - Use
$x("your-xpath")in console - Start simple - Build complex XPaths incrementally
- Check uniqueness - Verify your XPath returns only one element
- Use Chrome extensions - ChroPath, SelectorsHub help generate XPaths
- Practice interactively - Try the XPath tester at XPath Decoded to experiment with expressions
Performance Considerations
| Approach | Speed | Notes |
|---|---|---|
| ID | Fastest | Native browser optimization |
| CSS Selector | Fast | Well-optimized in browsers |
| Simple XPath | Good | //*[@id='x'] is fast |
| Complex XPath | Slower | Axes and functions add overhead |
| Text-based XPath | Slowest | Requires text node scanning |
Next Steps
- Relative Locators - Selenium 4’s spatial approach
- CSS Selectors - Often faster alternative
- Explicit Waits - Wait for elements to be ready