How Can I get text of all child nodes - xpath

I want to get the text of a tag and span tag at the same time.
<td class="desc_autoHeight">
<a rel="nofollow" href="#" target="_blank">Silicon Power</a>
<br><span class="FreeGift">48 Hours Only</span>
</td>
<td class="desc_autoHeight">
<a rel="nofollow" href="#" target="_blank">Silicon Power</a>
48 Hours Only
</td>
Result should be Silicon Power 48 Hours Only

Here is the xpath with concat
concat(//td[#class='desc_autoHeight']/a/text(), ' ', //td[#class='desc_autoHeight']//span[#class='FreeGift']/text())
Screenshot:

If $td is the td element in question, then normalize-space($td) gives you the string you are looking for, at least in this particular example.
In many cases simply using the string value of the element (which you can get using string(), but in many cases that's implicit) is adequate. The difference with normalize-space() is that it turns chunks of spaces and newlines (like the whitespace before the <a> start tag) into a single space, or eliminates it at the start and end.

Related

How do I get the text of a capybara element including leading whitespace.

I am trying to write an rspec/capybara/selenium spec that deals with verifying of whitespace. Basically I have a form that can be filled out and once it is saved, the information renders as a row in a table. The issue that I am having is that once I get to a certain td or span and I call .text on it, what is being returned is stripped of the leading and trailing white space. So if you look at the sample below, if I call find('#one').text what is returned is 'FOOO'. What I want to be returned is ' FOOO ' (I.E. including the leading and trailing whitespace).
<tr id="myRow">
<td id="one">
<span> FOOO </span>
</td>
<td id="two">
<span> BAR </span>
</td>
</tr>
The leading and trailing whitespace would be collapsed/ignored by your browser so Capybara does the same. If you want that whitespace to actually be visible in the browser you need to replace the spaces with non-breaking spaces ( ) in your HTML and then Capybara will return them as well.

XPath to select specific text inside of text block

I am trying to figure out a way to pull specific values out of a big long text block.
So far I have //td[#class="PadLeft10"] which returns me a big long value starting with the company name and ending with the "View More Info" piece.
I am trying to break my results up into segments, so for example I want my code to look for the words "Primary Contact:" and then return the text that follows that, ending at the <br/>.
I need to get the Company Name, which is always the first bit of text, then the Primary Contact, then the Address, then the Phone and Fax, then the Website, and the Organization type.
The problem is that not every record has all the values. As you can see, the second entry has the address and website, but the first one doesn't.
I am using the Dataminer Chrome Plugin, for anyone familiar with that. It has separate xpath for rows and columns, so I am going to try to make a bunch of different columns that correspond to each of the fields that I am looking for.
Any direction would be greatly appreciated.
<td align="left" valign="top" width="2%">
<script>
if (0 == 1) document.write('<img src="https://website.com" border="0" alt=""/>');
</script>
<br/><br/></td>
<td class="PadLeft10" align="left" valign="top" width="32%" style="padding-left: 15px;">
<span style="font-weight: bold;font-size: 12pt;"><br/>Company Name Here</span><br/>Primary Contact: Mr. Eric Cartman <br/>Phone: (555) 555-5555<br/>Fax: (333) 333-3333<span style="text-decoration: underline;color: #0000ff"></span><br/>Organization Type: Distributor Branch
<br/>
» View More Info<br/>
<br/>
</td>
<td align="left" valign="top" width="2%">
<script>
if (0 == 1) document.write('<img src="https://website.com" border="0" alt=""/>');
</script>
<br/><br/></td>
<td class="PadLeft10" align="left" valign="top" width="32%" style="padding-left: 15px;">
<span style="font-weight: bold;font-size: 12pt;"><br/>Other Company</span><br/>Primary Contact: Mr. Jimmy Valmer<br/>100 N Ohio St 2rd Fl<br/>Rochester, IN 54225<br/>United States<br/>Phone: (888) 888-8888<br/>Fax: (999) 999-9999<span style="text-decoration: underline;color: #0000ff"><br/>Web Site: http://www.companywebsite.com</span><br/>Organization Type: Financial Service
<br/>
» View More Info<br/>
<br/>
</td>
</tr>
<tr>
I am new to xpath, but the least i can say: if you are the creator of the html code, you absolutely need to change it to be more structured
like : Primary Contact:<span id/class='primaryContact'>..</span>
Or else, you can get the elements by this selector (to edit) //td[#class="PadLeft10"]//child::span//following-sibling::text()[1] split by ':' and then proceed, but this solution stay just a diy.
Any direction would be greatly appreciated.
As far as a direction, the sections within table cell that you mention are neither nested DOM items, nor sibling-type DOM nodes. Those are sequential html elements that require special processing.
<br/>Company Name Here</span>
<br/>Primary Contact: Mr. Eric Cartman
<br/>Phone: (555) 555-5555
<br/>...
Both xpath and regex can be leveraged for such a case.
You can select the text node you're looking for using a predicate and the contains function:
//td[#class="PadLeft10"]/text()[contains(., "Primary Contact:")]
Then you can get the substring using the substring-after function:
substring-after(
//td[#class="PadLeft10"]/text()[contains(., "Primary Contact:")],
'Primary Contact:'
)
And remove leading and trailing whitespace using normalize-space:
normalize-space(
substring-after(
//td[#class="PadLeft10"]/text()[contains(., "Primary Contact:")],
'Primary Contact:'
)
)

How do I find if there's a second element exists with the same name with selenium using XPath?

I already know the Text of an element in the table:
string title1 = Driver.FindElement(
By.XPath(
".//[#id='ctl00_ContentPlaceHolder1_BreakdownGridView_ctl02_TitleLabel']"
)).Text;
How do I verify if there's a second element in the table that has the same text as title1?
Here is my Table structure:
<tr class="alt" style="background-color:White;height:110px;">
<td>
<span id="ctl00_ContentPlaceHolder1_BreakdownGridView_ctl03_WindowStartLabel" tabindex="1">
01/13/2013
</span>
</td>
<td>
<span id="ctl00_ContentPlaceHolder1_BreakdownGridView_ctl03_ShowLabel" tabindex="1">
Lea‌​der of the Pack
</span>
</td>
<td>
<span id="ctl00_ContentPlaceHolder1_BreakdownGridView_ctl03_TitleLabel">
Love at First Bite
</span>
</td>
<td>
<span id="ctl00_ContentPlaceHolder1_BreakdownGridView_ctl03_PremiereLabel">
01/12/2013 22:00
</span>
</td>
...
</tr>
After getting title1 try implement logic something like below to find how many elements are there with the same text
int count=driver.findElements(By.xpath("//table[#id='urTable']//*[text()='"+title1+"']")).size();
Based on the count it is easy to find how many elements are there with same text.
In your table structure, doing an xpath query as below would select all the span tags.
//tr/td/span
Now, xpath can be used to select the span tags with specific text as follows:
//tr/td/span[text() = "Text you're matching against"]
/* in your case*/
//tr/td/span[text() = title1]
This is to get spans consist that text....(partial match)
int count= driver.FindElements(
By.XPath(
".//span[contains(text(),'"+titleOneText+"')]"
)).size();
This is to get spans text is same....(full match)
int count= driver.FindElements(
By.XPath(
".//span[text()='"+titleOneText+"']"
)).size();
Based on your question if same xpath value having 2 elements. Just see the static value of particular element and take as xpath. it will work definitely. for example
save & cancel button having same xpath value
driver.find_element_by_xpath("//*[#id='id_sav']")-save
driver.find_element_by_xpath("//*[#id='id_sav']")-cancel
here we can use static element value
driver.find_element_by_xpath("//a[text()='save']")-save
driver.find_element_by_xpath("//a[text()='cancel']")-cancel

Retrieving text from an element with children

I am trying to get the text "Weeeeee" but when i use //td[#class='something']/text() I got nothing
<td class="something">
<a href='http://www.google.com'>Google</a>
Weeeeee
<div>
<a>something</a>
</div>
</td>
Try
//td[#class='something']/text()[normalize-space() != ''][1]
as there are three text nodes in your example, the first and the last one consist of whitespace only.
Highlighted with square brackets:
<td class="something">[\n
----]<a href='http://www.google.com'>Google</a>[\n
----Weeeeee\n
----]<div>
<a>something</a>
</div>[\n
]</td>

How to get the preceding element?

<p class="small" style="margin: 16px 4px 8px;">
<b>
<a class="menu-root" href="#pg-jump">Pages</a>
:
<b>1</b>
,
<a class="pg" href="viewforum.php?f=941&start=50">2</a>
,
<a class="pg" href="viewforum.php?f=941&start=100">3</a>
...
<a class="pg" href="viewforum.php?f=941&start=8400">169</a>
,
<a class="pg" href="viewforum.php?f=941&start=8450">170</a>
,
<a class="pg" href="viewforum.php?f=941&start=8500">171</a>
<a class="pg" href="viewforum.php?f=941&start=50">Next.</a>
</b>
</p>
I want to catch a element containing 171. So basically the preceding element from the Next.
//a[.='Next.']//Not sure how to use preceding here
You can use this xpath:
//a[.="Next."]/preceding::a[1]
If I were to diagram it out, using an X to represent the current location, it would look like this:
------------------+------+------------------
preceding-sibling | self | following-sibling
------------------|------|------------------
last() ... 2 1 | X | 1 2 ... last()
------------------+------+------------------
//a[contains(text(), 'Next.')]/preceding::a[contains(text(), '171')]
Explanation of xpath: Using text method along with <a> tag and then move ahead with preceding keyword to locate the element 171
I know this is old and if you didn't know the containing element preceding the "Name." element this wouldn't be a solution for you. BUT, if you were wanting to find exactly that element and there are several "171" elements all over the page.
The way to distinguish it from the rest, you could use the following.
//p[b[contains(., 'Next.')]]//a[contains(., '171')]

Resources