Locating elements using XPath
XPath, the XML path language, is a query language for selecting nodes from an XML document. All the major browsers support XPath as HTML pages are represented as XHTML documents in DOM.
The XPath language is based on a tree representation of the XML document and provides the ability to navigate around the tree, selecting nodes using a variety of criteria.
Selenium WebDriver supports XPath for locating elements using XPath expressions or queries.
Locating elements with XPath works very well with a lot of flexibility. However, this is the least preferable locator strategy due its slow performance.
One of the important differences between XPath and CSS is, with XPath we can search elements backward or forward in the DOM hierarchy while CSS works only in a forward direction. This means that with XPath we can locate a parent element using a child element.
In this recipe, we will explore some basic XPath queries to locate elements and then examine some advanced XPath queries.
How to do it...
Let's explore some basic XPath expressions that can be used in Selenium WebDriver. Selenium WebDriver provides the xpath()
method for locating elements using XPaths.
Finding elements with absolute path
Similar to CSS absolute paths, XPath absolute paths refer to the very specific location of the element, considering its complete hierarchy in the DOM. Here is an example where Username Input field is located using the absolute path. While providing absolute path a space is given between the elements.
WebElement userName = driver.findElement(By.xpath("html/body/div/div/form/input"));
However, this strategy has limitations as it depends on the structure or hierarchy of the elements on a page. If this changes, the locator will fail to get the element.
Finding elements with relative path
With relative path, we can locate an element directly irrespective of its location in the DOM. For example, we can locate the Username Input field in the following way, assuming it is the first <input>
element in the DOM:
WebElement userName = driver.findElement(By.xpath("//input"));
Finding elements using index
In the previous example, the XPath query will return the first <input>
element that it finds in the DOM. There could be multiple elements matching the specified XPath query. If the element is not the first element, we can also locate the element by using its index in DOM. For example in our login form, we can locate the Password field which is the second <input>
element on the page in the following way:
WebElement userName = driver.findElement(By.xpath("//input[2]"));
Finding elements using attributes values with XPath
Similar to CSS, we can also locate elements using their attribute values in XPath. In the following example, the Username field is located using the ID attribute:
WebElement userName = driver.findElement(By.xpath("//input[@id='username']"));
Here is another example where the image is located using the alt
attribute:
WebElement previousButton = driver.findElement(By.xpath("img[@alt='Previous']"));
You might come across situations where one attribute may not be sufficient to locate an element and you need combined additional attributes for a precise match. In the following example, multiple attributes are used to locate the <input>
element for the Login button:
WebElement previousButton = driver.findElement(By.xpath("//input[@type='submit'][@value='Login']"));
The same result can be achieved by using XPath and
operator.
WebElement previousButton = driver.findElement(By.xpath("//input[@type='submit'and @value='Login']"));
In the following example, either of the attributes is used to locate the elements using XPath or
operator:
WebElement previousButton = driver.findElement(By.xpath("//input[@type='submit'or @value='Login']"));
Finding elements using attributes with XPath
This strategy is a bit different from the earlier strategy where we want to locate elements based only on the specific attribute defined for them but not attribute values. For example, we want to lookup all the <img>
elements that have the alt
attribute specified.
List<WebElement> imagesWithAlt = driver.findElements(By.xpath ("img[@alt]"));
Performing partial match on attribute values
Similar to CSS selector, XPath also provides a way to locate elements matching partial attribute values using XPath functions. This is very useful for testing applications where attributes values are dynamically assigned and change every time a page is requested. For example, ASP.NET applications exhibit this kind of behavior where IDs are generated dynamically. The following table explains the use of these XPath functions:
Syntax |
Example |
Description |
---|---|---|
|
|
Starting with: For example, if the ID of an element is |
|
|
Ending with: For example, if the ID of an element is |
|
|
Containing: For example, if the ID for an element is |
Matching any attribute using a value
XPath matches the attribute for all the elements for a specified value and returns the element. For example, in the following XPath query, 'userName'
is specified. XPath will check all the elements and their attributes to see if they have this value and return the matching element.
WebElement userName = driver.findElement(By.xpath("//input[@*='username']"));
Locating elements with XPath axis
XPath axes help to locate elements based on the element's relationship with other elements in a document. Here are some examples for some common XPath axes used to locate elements from a <table>
element. This can be applied to any other element structure from your application.
Here is the graphical representation of the HTML elements:
Axis |
Description |
Example |
Result |
---|---|---|---|
|
Selects all ancestors (parent, grandparent, and so on) of the current node. |
|
This will get the table element. |
|
Selects all descendants (children, grandchildren, and so on) of the current node. |
|
This will get the input element from the third column of the second row from the table. |
|
Selects everything in the document after the closing tag of the current node. |
|
This will get the second row from the table. |
|
Selects all siblings after the current node. |
|
This will get the second column from the second row immediately after the column that has |
|
Selects all nodes that appear before the current node in the document, except ancestors, attribute nodes, and namespace nodes. |
|
This will get the header row. |
|
Selects all siblings before the current node. |
|
This will get the first column of third row from the table. |
You can find more about XPath axis at http://www.w3schools.com/xpath/xpath_axes.asp.
How it works...
XPath is a powerful language for querying and processing DOM in browsers. XPath is used to navigate through elements and attributes in a DOM. XPath provides rules, function, and syntax to locate the elements.
The majority of browsers support XPath and Selenium WebDriver provides the ability to locate elements using the XPath language.
Using the xpath()
method of the By
class we can locate elements using XPath syntax. XPath is little slower than the CSS selectors as XPath provides the ability to search elements bi-directionally. You can search for the parent element if you know the child or you can locate a child element using its relationship with the parent and siblings.
Using XPath, a test can locate elements in multiple ways based on the structure of the document, attribute values, text contents and so on, as described in this recipe.