XPath Cheat Sheet: Complete Syntax Reference
A practical XPath cheatsheet with syntax, axes, operators, and functions. Built for Selenium engineers, Playwright testers, web scrapers, and anyone who needs a fast XPath reference without digging through specifications.
Core syntax
Basics
//tag— anywhere in the document./html/body/div[1]— absolute path to first div.//div[@id='main']— attribute equals.//div[contains(@class, 'btn')]— partial attribute.//div[text()='Save']— exact text.//div[normalize-space()='Save']— trim whitespace.
Predicates
//ul/li[1]— first item.//ul/li[last()]— last item.//ul/li[position() < 3]— first two items.//table//tr[td[contains(., 'Paid')]]— row filter.//div[count(p) > 2]— count function.
Axes reference
| Axis | Usage | Example |
|---|---|---|
| child | child::node() | //div/child::p |
| parent | parent::node() | //button/parent::* |
| self | self::node() | //div/self::div |
| descendant | descendant::node() | //ul/descendant::li |
| descendant-or-self | descendant-or-self::node() | //section/descendant-or-self::span |
| ancestor | ancestor::node() | //input/ancestor::form |
| ancestor-or-self | ancestor-or-self::node() | //li/ancestor-or-self::ul |
| following | following::node() | //h2/following::p[1] |
| following-sibling | following-sibling::node() | //label/following-sibling::input |
| preceding | preceding::node() | //h2/preceding::p[1] |
| preceding-sibling | preceding-sibling::node() | //input/preceding-sibling::label |
| attribute | @attr | //a/@href |
| namespace | namespace::node() | //svg/namespace::* |
Tip: combine axes for readability, e.g., //label[text()='Email']/following-sibling::input.
Operators
| Operator | Meaning | Example |
|---|---|---|
| = | Equal | //input[@type='email'] |
| != | Not equal | //div[@role!='alert'] |
| < | Less than | //price[@amount<100] |
| <= | Less or equal | //item[position()<=3] |
| > | Greater than | //score[@value>80] |
| >= | Greater or equal | //price[@amount>=10] |
| + | Add | //p[position()+1] |
| - | Subtract | //li[last()-1] |
| * | Multiply | //item[@price*2] |
| div | Divide | //order[@total div 2] |
| mod | Modulo | //li[position() mod 2=0] |
| | | Union | //div | //span |
Selenium patterns (15)
Button by text
//button[text()='Submit']
Link by href
//a[@href='/login']
Input by name
//input[@name='username']
Table cell
//table//tr[2]//td[3]
Last list item
//ul[@class='menu']/li[last()]
Multi-class error
//div[contains(@class,'error') and contains(@class,'visible')]
OR condition
//button[@type='submit' or @class='submit-btn']
No class paragraphs
//*[@id='main']//p[not(@class)]
Data-test container
//div[@data-test-id='login-form']//input
Iframe content
//iframe[@name='content']//*
Selected option
//select[@name='country']/option[@selected]
Checked checkbox
//input[@type='checkbox' and @checked]
Dynamic ID
//div[starts-with(@id, 'dynamic-')]
Error text
//span[contains(text(), 'Error') and @class='msg']
Parent button
//*[text()='Next']/parent::button
Functions reference
String functions
contains()— contains(@class, 'btn')starts-with()— starts-with(@id, 'user-')substring()— substring(text(), 1, 5)substring-before()— substring-before(@href,'?')substring-after()— substring-after(@href,'=')string-length()— string-length(text())>10concat()— concat(@first,'-',@last)normalize-space()— normalize-space(text())translate()— translate(@class,'ABC','abc')text()— //p[text()='Hello']
Number functions
count()— count(//div)sum()— sum(//item/@price)number()— number(@value)floor()— floor(3.7)ceiling()— ceiling(3.2)round()— round(3.5)
Boolean functions
boolean()— boolean(@checked)not()— not(@disabled)true()— true()false()— false()
Node functions
name()— name() = 'div'local-name()— local-name() = 'svg'namespace-uri()— namespace-uri()position()— position() = 1last()— //div[last()]
Common patterns
Selenium automation
- Prefer @data-test-id to avoid copy churn.
- Scope to a parent container to reduce match count.
- Use normalize-space() for button text.
Web scraping
- Collect attributes directly: //a/@href.
- Filter ads: //div[not(contains(@class,'ad'))].
- Pick top results: //ul/li[position()<=3].
Debugging
- Test in browser console: $x("//button")
- Leverage the playground for counts and preview.
- Use contains() + starts-with() on dynamic values.
Need interactive practice? Jump to the XPath tutorial or load examples in the XPath playground.