Reputation: 45
I am running tests in Java Selenium where I find an element, and once found need to find the immediately preceding element. The code needs to be dynamic because I don't know if the element I start from is the 3rd out of 5, the 6th out of 10, or the 1st out of 2.
The problem is, using preceding-sibling from xpath, I get all elements preceding the found element, not the one immediately preceding it. For example, this is my xml:
<div>
<input formcontrolname="myValues" id="value1" type="radio" value="VALUE1" />
<label for="value1">Value 1</label>
<input formcontrolname="myValues" id="value2" type="radio" value="VALUE2" />
<label for="value2">Value 2</label>
</div>
Lets say I have found the 'Value 2' label as a WebElement, then I want to do next is find the specific input immediately preceding that label (id='value2'). Since it has to be relative to the label I've found, I can't just find by that id; I don't really know the id, just that the input is supposed to precede the label. I thought I could use this:
WebElement input = element.findElement(By.xpath("preceding-sibling::input"));
But that xpath actually returns all the inputs that are siblings of the label. So, in the example, I get an array of two inputs returned, both 'value1' and 'value2'. Selenium sets the value of input to be the input with id='value1', the first in the returned array.
So my question is, is there an xpath that will return the one element that immediately precedes a given element?
Upvotes: 3
Views: 19094
Reputation: 193308
As per the HTML you have shared to locate the <input>
with id="value2"
with respect to <label>
with Value 2
you can use the following xpath
:
.//preceding::input[1]
I still feel you haven't been able to express/put-up your exact use-case/requirement properly. A possible use-case for you may be to invoke click()
on a Radio Button i.e. on a <input>
tag with respect to a Label i.e. a <label>
tag. If this is your usecase a better way would be to write a function as follows :
public void click_radio_button(String label_text)
{
driver.findElement(By.xpath("//label[.='" + label_text + "']//preceding::input[1]")).click();
}
Now from your main()
or @Test
annotated class you can call the function click_radio_button()
passing the Label Text as an argument to click()
on the respective Radio Button as follows :
click_radio_button("Value 1")
click_radio_button("Value 2")
Finally, why should you have chosen preceding over preceding-sibling ?
As per the HTML all of the <input>
and <label>
nodes are on the same step as follows :
<div>
<input formcontrolname="myValues" id="value1" type="radio" value="VALUE1" />
<label for="value1">Value 1</label>
<input formcontrolname="myValues" id="value2" type="radio" value="VALUE2" />
<label for="value2">Value 2</label>
</div>
Ideally,
preceding-sibling::parentNode/childNode[n]
(which is not your usecase
)preceding should have the prototype of preceding::node[n]
(which exactly matches your usecase
)
Here you can find a detailed discussion on Which should I use: preceding:: or preceding-sibling::?
Upvotes: 0
Reputation: 161
I'm a bit confused on what you're telling to the driver to reference. 'findElement(By.xpath("preceding-sibling::input"));' isn't specifying WHAT it should precede.... so if all you're looking to do is find everything preceding any element with an id of 'value,' you're code should look something like this:
driver.find_elements_by_xpath("//*[contains(@id, 'value')]]/preceding-sibling::input");
Now the syntax assumes you know where your semi-colons, parentheticals, etc should be... I apologize in advance if my syntax isn't right. I write selenium, but only in Python.
Upvotes: 0
Reputation: 52685
You can get required result by specifying the index:
./preceding-sibling::input[1]
In this case you'll get the first (immediate) preceding-sibling of type "input"
Upvotes: 4