I am trying to locate a specific element on a page but cannot figure out the proper Xpath to use.
Here is the HTML (note that the location of each div can vary):
<div>
<label>First Name</label>
<span class="metadataField metadataFieldReadonly">
<input type="text" name="some-random-value" value="John">
</span>
</div>
<div>
<label>Last Name</label>
<span class="metadataField metadataFieldReadonly">
<input type="text" name="some-random-value" value="Smith">
</span>
</div>
So what I am trying to locate the INPUT element that is the //div/span[#class='metadataField metadataFieldReadonly']/input in the same div that has a //div/label[text()='Last Name']
I can successfully locate the label with this (using JAVA):
driver.findElement(By.xpath("//div/label[text()='Last Name']")).click();
And I can successfully locate the first input under the first element (but I may not always want the first element) with this:
driver.findElement(By.xpath("//div/span[#class='metadataField metadataFieldReadonly']/input")).click();
So the problems are that (i) the name tag and value of the INPUT are always different so they cannot be used to pick the element, and (ii) the div with the last name label may not always be the second one, and (iii) the label and span are the same level (siblings) so I cannot figure out how to properly create the Xpath statement.
So in words, I need to find the input of the span in the same div that has a label with 'Last Name' in it.
So I need to know how to combine these two XPath statements into one complex statement (assuming they are in the same div and that the label and span are siblings):
//div/label[text()='Last Name']
//div/span[#class='metadataField metadataFieldReadonly']/input
Thanks
That's downright easy: //div[label[text()='Last Name']]/span[#class='metadataField metadataFieldReadonly']/input - literally, "the input contained in the span with the metadataField and metadataFieldReadonly classes contained in the div that contains the label with the text 'Last Name'". So you're using the label to locate the div and then building from it to the input you want.
To be a more robust, you shouldn't count on the ordering of the class names - that isn't guaranteed by the specs. So something like this would be stronger: //div[label[text()='Last Name']]/span[contains(concat(' ', #class,' '),' metadataField ') and contains(concat(' ',#class,' '),' metadataFieldReadonly ')]/input.
Related
I am using Java and Selenium to write a test. I have this at DOM:
...
<div class='a'>
<div class='b'>
<div class='1'></div>
<div class='2'></div>
</div>
/div>
...
I am using this Xpath:
//div[#class='a']//div[2]
to get to <div class='1'></div>
but I am taken to:
<div class='2'></div>
in simple words please explain why and how to handle this situation. I do know I can use the class attribute to get to an element like :
//div[#class='1']
but I want to use numbers in bracket style like div[and-a-number-here]
Is there any way to get all divs under a tag and the select the one by the number?
In your xpath:
//div[#class='a']//div[2]
you are searching for any div which is second descendant of the div with a class=a. That's why it's returning you the 2nd div with class=2.
To get the desired element use xpath like this:
//div[#class='a']/div/div[1]
I have a structure like this:
<div>
<div>
<span class="">TextA</span>
</div>
<div>
<span class="">TextB</span>
</div>
</div>
I can find element span with TextA, and from there, I want to find span with textB, then click on it (which is not available to find it alone). So I used xpath like this:
webDriver.findElement(By.xpath("//span[contains(.,'TextA')]/following-sibling::span")).click();
I got exception Element is not found. I assumed these spans are siblings ?!. Can anyone help me in this case. Thanks
I got exception Element is not found. I assumed these spans are siblings ?
These two spans are not siblings - they are children of different elements and cannot be siblings.
Instead of following-sibling, you may use the following axis:
//span[contains(.,'TextA')]/following::span
Or, you may get the div element that contains the span with TextA text and then get it's following sibling:
//div[contains(span, 'TextA')]/following-sibling::div/span
The <span>'s aren't siblings. if the <span>'s were siblings, they'd have to be adjacent.
for example:
<div>
<div>
<span class="">TextA</span>
<span class="">TextB</span>
</div>
</div>
In this case, they are siblings and your selector would work.
The elements that are actually siblings, are the <div>s.
The xpath that could work for you, would be:
//span[contains(.,'TextA')]/../following-sibling::div/span
<span class="label label-danger" style="font-size : 13px; font-weight : 400;">Critical</span>
Below is the xpath which I am using:
.//tr[#data-index='0']/td/span
I have a line in HTML source like above. So, I have used corresponding Xpath and used getText() method to get the text i.e. Critical. I am succeed in that.
But, I have another line in another page like this.
<div class="col-xs-12">
<div id="project-update-success-information" class="panel-confirmation success" style="display: none;">
<span class="fa fa-check"/>
Project Updated
</div>
Below is the xpath which I am using:-
.//*[#id='project-update-success-information']/span
I have used the corresponding Xpath and getText(),but unfortunately it doesn't retrieve the text for me. I doubted that there is no </span> close tag in the second line which causes the problem. Is there any other way to get the text?
This question has many answers already, but none of them really explains the problem. First, let us get your initial confusion about self-closing elements out of the way, before moving on to the real problem: No, it is not a problem that an element like
<span class="fa fa-check"/>
does not have a </span> tag. There is no need to indicate where it ends because the /> already tells you that this element does not contain anything and closes at this point.
Then let's look at only the fragment of the document that you show:
<div class="col-xs-12">
<div id="project-update-success-information" class="panel-confirmation success" style="display: none;">
<span class="fa fa-check"/>
Project Updated
</div>
</div>
An XPath expression like (note that most likely you do not need the . at the very beginning of the expression):
//*[#id='project-update-success-information']
will return the inner div element with all that it contains. What it does contain is, exactly in this order:
a whitespace-only text node
a self-closing span element with no content other than an attribute
the text node that contains "Project Updated"
So, it is not at all surprising that when you select the inner div and use .getText(), you end up with 2 text nodes in the result. Another way to get at the text content of an element is by using text() in the XPath expression:
//*[#id='project-update-success-information']/text()
which will return (individual elements separated by --------):
[whitespace-only text node]
-----------------------
Project Updated
The solutions are either
use getText() to retrieve all text nodes and later exclude those that only contain whitespace or
use an XPath expression that targets text nodes directly and excludes the ones that only contain whitespace. The standard way of doing this is with [normalize-space()]:
//*[#id='project-update-success-information']/text()[normalize-space()]
Note that, in general, there is no guarantee that the text content of an element will be in one single text node. It is very likely that you will sometimes encounter HTML or XML where elements have several text nodes, all of them containing non-whitespace characters, e.g.:
<div>
Project
<span/>
Updated
</div>
Try this text() method like below:-
//span[#class='fa fa-check']/text()
Hope it will help you :)
The element is empty and thus contains no text
<span class="fa fa-check"/>
If on the other hand it was like
<span class="fa fa-check">Some content</span>
then it would, as in yor first attempt, contain some text.
Without knowing more of the content I would try another xpath method: following-sibling.
Try:
driver.findElement(By.className("panel-confirmation success")).getText();
Question is for JAVA + Selenium:
My HTML is:
<section class="d-menu d-outclass-bootstrap unclickable d-apps d-app-list">
<section class="standard-component image-sequence-button" tabindex="0" role="link">
<div class="image-region">
<div class="core-component image">...
</div>
<div class="sequence-region">
<div class="core-component section">
<div>
<section class="standard-component text hide-section-separator-line">
<div class="text-region">
<div class="core-component text">
<span class="main-text">BART Times</span>
<span class="sub-text">Provider</span>
</div>
</div>
</section>
<section class="standard-component speech-bubble hide-section-separator-line">...
<section class="standard-component text">...
</div>
</div>
</div>
<div class="button-region">
<div class="core-component button" tabindex="0" role="link">...
</div>
</section>
<section class="standard-component image-sequence-button" tabindex="0" role="link">...
<section class="standard-component image-sequence-button" tabindex="0" role="link">...
<section class="standard-component image-sequence-button" tabindex="0" role="link">...</section>
EDIT:
All <section class="standard-component image-sequence-button"... have exact same structure and hierarchy (same attributes for all tags). The only thing that changes are the TEXT values of the tags(e.g. span)
PART1:
I'm looking for various elements inside the second section tag. So, What I'm trying to do is get the <span class="main-text"> which has a value BART Times because of the business requirement.
I already know how to get it via xpath:
My xpath (verified via firebug):
"//section//div[#class = 'sequence-region']//section[#class = 'standard-component text hide-section-separator-line']//span[#class = 'main-text' and text() = '%s']"
I can get the span tag via checking for %s values (e.g. BART Times).
However, due to design considerations, we've been told to use CSS only. So, I tried to come up with a CSS counterpart for the above xpath but did not find it.
The following CSS
"section div.sequence-region section.standard-component.text.hide-section-separator-line span[class=main-text]"
returns all the span tags under all the section tags.
Question1: How do I get the span tag which has a certain TEXT value (the %s part of xpath)?
Things I've tried for that last span tag which did not worked(according to the firebug):
span.main-text[text='BART Times']
span[class=main-text][text='BART Times']
span.main-text:contains('BART Times')
span[class=main-text]:contains('BART Times')
span.main-text[text="BART Times"]
span[class=main-text][text="BART Times"]
span.main-text[text=\"BART Times\"]
span[class=main-text][text=\"BART Times\"]
span[text="BART Times"]
span[text=\"BART Times\"]
span:contains('BART Times')
span:contains("BART Times")
span:contains(\"BART Times\")
So, basically I want to put a check on BOTH class and TEXT value of the span tag in CSS selector.
Part 2:
Then I want to get the <section class="standard-component image-sequence-button"... element where I found the <span class="main-text"> and then find other elements inside that specific section tag
Question 2:
Assuming, I found the span tag in question 1 via CSS, how do I get the section tag (which is a super--- parent of the span tag)?
If CSS is not possible, please provide an xpath counterpart for this as a workaround for a while.
CSS selectors can't select based on text. The answers to Is there a CSS selector for elements containing certain text? go into detail on why.
To select based on class and text in xpath: //span[contains(#class, 'main-text') and text() = 'BART Times']
Regarding question 1, it is not possible, as stated in the other answer here. This is another thread about the topic : CSS selector based on element text?
Regarding question 2, once again there is no such parent selector in XPath : Is there a CSS parent selector?. Now for the xpath counterpart, you can use parent axis (parent::*) or shortcut notation for the same (..), or put the span selector as predicate for the parent (the third example below) :
....//span[#class = 'main-text' and text() = '%s']/parent::*
....//span[#class = 'main-text' and text() = '%s']/..
....//*[span[#class = 'main-text' and text() = '%s']]
See the following thread for some better (yet more complicated) alternative to match element by CSS class using XPath, just in case you haven't came across link on this topic : How can I find an element by CSS class with XPath?
I wrote some codes to parse the html using xpath and Java. The html file is something like:
<div class="field_row">
<label for="names">Names *</label>
<input id="address.A" type="text" maxlength="15" size="32" value="12345" name="address.work">
<span class="additional_info"> Information 1 </span>
</div>
<div class="field_row">
<label for="names">Names *</label>
<input id="address.B" type="text" maxlength="15" size="32" value="12345" name="address.work">
<span class="additional_info"> Information 2 </span>
</div>
And Java codes:
public static final Element INFOFIELD= Element.findXPath(".//*[#class='additional_info'");
will let me get 'Information 1'; however, I need to retrieve 'Information 2'. Therefore, I use:
public static final Element INFOFIELD= Element.findXPath(".//*[#class='additional_info' and #id='address.B']");
But got errors. Could you give me some hint please? Thanks. A.
You can create an XPath based on your input field (address.B), and then specify you want to access one of its sibling nodes and thus retrieve its data...
XPath:
//input[#id='address.B']/following-sibling::span[#class='additional_info']
as you can see after we find the input node with the id attribute 'address.b', we specify 'following-sibling'. This indicates that we want to select one of the siblings after the current node('address.B's input field). Then we specify which node that is followed by the attribute details: span[#class='additional_info']
some working code implementing the above XPath:
WebElement element = driver.findElement(By.xpath("//input[#id='address.B']/following-sibling::span[#class='additional_info']"));
System.out.println(element.getText());
will print 'Information 2'
You can use XPath axes in other related ways to access other nodes in the DOM (parents, children, siblings,etc).
http://www.w3schools.com/xpath/xpath_axes.asp
An axis defines a node-set relative to the current node.