XPath OR Condition: Matching Either of Multiple Conditions

Match either of several XPath conditions with or, group alternatives with parentheses, negate them with not(), and use them in Selenium.

To match an element when either of several conditions is true, join the conditions with or inside a predicate—the expression between square brackets:

//input[@type='email' or @type='tel']

Only one condition joined by or needs to be true. This expression selects input elements whose type is either email or tel.

These examples use XPath 1.0-compatible syntax (or, and, not(), contains(), normalize-space()), which is what browsers, Selenium and most scrapers support. XPath has no || operator.

If every condition must be true instead, use and—covered in the companion guide on the XPath AND condition.

XPath OR condition

Use or between any two conditions that are each acceptable on their own:

//button[@type='submit' or @role='button']

Chain more than two alternatives the same way:

//input[@type='text' or @type='email' or @type='tel']

Use lowercase or. Uppercase OR raises a syntax error in most engines.

or also works with element tests, not just attributes. To select rows inside either a table header or body:

//table[@id='results']/*[self::thead or self::tbody]/tr

The self:: axis checks the current element selected by *.

OR across attribute values

Match either of two attribute values:

//*[@role='alert' or @role='status']

Match either of two different attributes:

//*[@data-testid='save' or @aria-label='Save changes']

Combine attribute and text alternatives:

//button[@type='submit' or contains(normalize-space(.), 'Save')]

normalize-space(.) trims leading and trailing whitespace and collapses repeated whitespace before checking the element’s full text content. That form is XPath 1.0-safe and usually better than text() when text is split across child nodes.

Group OR conditions with parentheses (precedence)

In XPath, and binds more tightly than or. Mixed expressions need parentheses so the intended alternatives stay together:

//input[(@type='text' or @type='email') and not(@disabled)]

This finds text or email inputs that are not disabled. Without the parentheses, the engine groups the expression as:

@type='text'  or  (@type='email' and not(@disabled))

That would still match a disabled text input, because the first alternative alone is enough for or.

Keep related alternatives inside parentheses and apply shared restrictions outside them. The XPath AND guide covers the same precedence rule from the other direction, including stacked [a][b] predicates.

Negate an OR expression with not()

Wrapping an or expression in not() excludes elements that match any of the alternatives:

//a[not(contains(., 'Delete') or contains(., 'Edit'))]

That reads as: links whose text contains neither Delete nor Edit. It is equivalent to chaining not() with and:

//a[not(contains(., 'Delete')) and not(contains(., 'Edit'))]

Use whichever form reads more clearly for the number of alternatives involved. Both are valid XPath 1.0.

Selenium example

from selenium.webdriver.common.by import By

field = driver.find_element(
    By.XPATH,
    "//input[@type='email' or @type='tel']",
)

When the XPath string contains quotes, use the opposite quote style for the Python string or escape the inner quotes.

Common XPath OR errors

  • Use lowercase or—there is no || in XPath 1.0.
  • Use contains(), not contain().
  • Put logical expressions inside [...] predicates.
  • Balance every bracket and parenthesis.
  • Prefer . (or normalize-space(.)) over bare text() when text is split across children.
  • XPath uses =, not ==.
  • Group or alternatives in parentheses before combining them with and.

Quick reference

RequirementPattern
Either matches//*[@a or @b]
Any of three matches//*[@a or @b or @c]
Either element type//*[self::thead or self::tbody]
Either matches, plus a shared restriction//*[(@a or @b) and not(@c)]
Neither matches//*[not(@a or @b)]
Text contains either value//*[contains(., 'x') or contains(., 'y')]

Start with the simplest reliable expression, then add one alternative at a time. When the requirement flips to every condition being true, switch to the XPath AND condition.