Is it possible in XPATH to find an element by attribute value, not by name?

Viewed 209

For example I have an XML element:

<input id="optSmsCode" type="tel" name="otp" placeholder="SMS-code">

Suppose I know that somewhere there must be an attribute with otp value, but I don’t know in what attribute it can be, respectively, is it possible to have an XPath expression of type like this:

.//input[(contains(*, "otp")) or (contains(*, "ode"))]
2 Answers

Try it like this and see if it works:

one = '//input/@*[(contains(.,"otp") or contains(.,"ode"))]/..'
print(driver.find_elements_by_xpath(one))

Edit:

The contains() function has a required cardinality of first argument of either one or zero. In plain(ish) English, it means you can check only one element at a time to see if it contains the target string.

So, the expression above goes through each attribute of input separately (/@*), checks if the attribute value of that specific attribute contains within it the target string and - if target is found - goes up to the parent of that attribute (/..) which, in the case of an attribute, is the node itself (input).

This XPath expression selects all <input> elements that have some attribute, whose string value contains "otp" or "ode". Notice that there is no need to "go up to the parent ..." enter image description here

//input[@*[contains(., 'otp') or contains(., 'ode')]]

If we know that "otp" or "ode" must be the whole value of the attribute (not just a substring of the value), then this expression is stricter and more efficient to evaluate:

//input[@*[. ='otp' or . = 'ode']]

In this latter case ("otp" or "ode" are the whole value of the attribute), if we have to compare against many values then an XPath expression of the above form will quickly become too long. There is a way to simplify such long expression and do just a single comparison:

//input[@*[contains('|s1|s2|s3|s4|s5|', concat('|', ., '|'))]]

The above expression selects all input elements in the document, that have at least one attribute whose value is one of the strings "s1", "s2", "s3", "s4" or "s5".

Related