No text returned for IWebElement.Text - c#

I have some xpath which correctly returns me the nodes I am after but I cannot retrieve the text between the tags in Selenium.
The below correctly returns the 4 nodes I am after:
var subMenuItems = driver.FindElements(By.XPath("//div[#id='OpenandApply123']//a"));
However when I do the below I get nothing for text returned when I'm expecting "abc123":
string item1 = subMenuItems[0].Text;
How do I get the texts for abc123, def123 etc, returned?
Full html below, apologies for formatting:
<div class="subMenu" id="OpenandApply123" role="menu" aria-hidden="false" style="" xpath="1">
<table cellpadding="0" cellspacing="0" width="150" role="presentation">
<tbody><tr role="presentation">
<td role="presentation" class="">
<a id="abc.feature_link" href="abc/abc" class="menuItem" target="_top" style="background-position: 4px 2px;">
abc123
</a>
</td>
</tr>
<tr role="presentation">
<td role="presentation" class="">
<a id="def.feature_link" href="abc/Feature/def" class="menuItem" target="_top" style="background-position: 4px 2px;">
def123
</a>
</td>
</tr>
<tr role="presentation">
<td role="presentation">
<a id="ghi.feature_link" href="abc/Feature/ghi" class="menuItem" target="_top" style="">
ghi123
</a>
</td>
</tr>
<tr role="presentation">
<td role="presentation">
<a id="klm.feature_link" href="abc/klm" class="menuItem" target="_top" style="">
klm123
</a>
</td>
</tr>
</tbody></table>
</div>

I would suggest induce WebDriverWait and wait for VisibilityOfAllElementsLocatedBy() and following xpath.
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
wait.Until(SeleniumExtras.WaitHelpers.ExpectedConditions.VisibilityOfAllElementsLocatedBy(By.XPath("//td[#role='presentation']//a")));
var subMenuItems = driver.FindElements(By.XPath("//td[#role='presentation']//a"));
string item1 = subMenuItems[0].Text;
Or
string item1 = subMenuItems[0].GetAttribute("textContent");

Related

Knockout.js Binding param to Data-Target returning object instead of text (Accordion)

New to Knockout.Js and just about getting my head around the data-bindings after three days...
I have created a dynamic accordion and when doing my data-bind with the attr: {'data-target': '#' + RecipeName' i get back Data-target=#[object object] I understand that i can get back the name
of the parameter if i used data-bind="text: RecipeName" (But i need to append the # to it
to allow my accordion to be opened on the correct Id..)
I have looked online and i can't seem to find a sufficient answer. I have tried google
dev tools to change the #[object object] to the value im expecting and it works fine.
Please can someone explain why this happens and what is needed to resolve.. I guess its pretty straight forward?
<section id="results" style="margin-top: 1em;">
<div class="accordion-group">
<div class="accordion-heading">
<table class="table table-striped table-hover accordion">
<thead>
<tr>
<th>Set Next</th>
<th>Name</th>
<th>Bench</th>
<th>Transacted</th>
<th>Receipe Name</th>
</tr>
</thead>
<tbody data-bind="foreach: Stages">
*****<tr class="accordion-toggle" data-toggle="collapse" data-target="#" data-bind="attr: {'data-target': '#' + RecipeName}">*****
<td data-bind="css: CellClass">
<button class="btn btn-warning" data-bind="attr: {'data-id': Id}" data-toggle="modal" data-target="#moveReason">#Html.LocalisedStringFor(model => model.MoveToStageText)</button>
<a class="text" data-bind="attr: {'data-id': Id}" data-toggle="modal" data-target="#moveReason"><span>#Html.LocalisedStringFor(model => model.CurrentPositionText)</span></a>
</td>
<td><span data-bind="text: ProcessName"></span></td>
<td><span data-bind="text: BenchName"></span></td>
<td><span data-bind="text: TransactionStatus"></span></td>
<td><span data-bind="text: RecipeName"></span></td>
</tr>
<tr id="" class="accordion-body collapse" data-bind="attr: {'id':RecipeName}">
<td colspan="5">
<div class="accordion-inner" data-bind="foreach: $parent.Stages">
<ul>
<li> <span data-bind="text: StepName"></span></li>
<button class="btn btn-warning" data-bind="attr: {'data-id': Id}" data-toggle="modal" data-target="#moveReason">#Html.LocalisedStringFor(model => model.MoveToStageText)</button>
</ul>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</section>
This is the result it returns
I suspect that <tr class="accordion-toggle" data-toggle="collapse" data-target="#" data-bind="attr: {'data-target': '#' + RecipeName}">
needs to be
<tr class="accordion-toggle" data-toggle="collapse" data-target="#" data-bind="attr: {'data-target': '#' + RecipeName()}">
the other option would be to put a property on your viewmodel that does the logic you need like
function ViewModel(){
var self = this;
self.RecipeName = ko.observable();
self.RecipeNameHash = ko.pureComputed(function(){
return '#' + self.RecipeName();
});
}
then the table row becomes
<tr class="accordion-toggle" data-toggle="collapse" data-target="#" data-bind="attr: {'data-target': RecipeNameHash}">

Remove Portion of HTML in EWS EmailMessage Body

I would like to remove a portion of HTML content of EWS EmailMessage .Body.Text value before replying via ResponseMessage in C#
The content to remove are as follows, and they contain clickable and non-clikable html buttons.
I see that we can't declare our own custom tags, so I am unable to use string.replace by locating custom html tags.
May I know if there are workarounds for my task, such as placing the content below in a placeholder, etc?
<table class="MsoNormalTable" border="0" cellspacing="0" cellpadding="0" width="100%" style="width:100.0%">
<tbody>
<tr>
<td style="padding:0in 0in 0in 0in">
<p class="MsoNormal"><span style="font-size:12.0pt;font-family:"Times New Roman",serif"> <o:p></o:p></span></p>
</td>
<td width="30%" style="width:30.0%;background:#17202A;padding:4.5pt 4.5pt 4.5pt 4.5pt;display:inline-block">
<p class="MsoNormal" align="center" style="text-align:center"><b><span style="font-size:11.5pt;font-family:"Helvetica",sans-serif;color:white">ACTION: ADD
<o:p></o:p></span></b></p>
</td>
<td style="padding:0in 0in 0in 0in">
<p class="MsoNormal"><span style="font-size:12.0pt;font-family:"Times New Roman",serif"> <o:p></o:p></span></p>
</td>
<td width="30%" style="width:30.0%;background:#17202A;padding:4.5pt 4.5pt 4.5pt 4.5pt;display:inline-block">
<p class="MsoNormal" align="center" style="text-align:center"><b><span style="font-size:11.5pt;font-family:"Helvetica",sans-serif;color:white">ACTION: MINUS
<o:p></o:p></span></b></p>
</td>
<td style="padding:0in 0in 0in 0in">
<p class="MsoNormal"><span style="font-size:12.0pt;font-family:"Times New Roman",serif"> <o:p></o:p></span></p>
</td>
<td width="20%" style="width:20.0%;background:#3A69C2;padding:4.5pt 4.5pt 4.5pt 4.5pt;display:inline-block">
<p class="MsoNormal" align="center" style="text-align:center"><b><span style="font-size:11.5pt;font-family:"Helvetica",sans-serif;color:white"><a href="mailto:test.com?subject=[MULTIPLY];body=ACTION:%20MULTIPLY"><span style="color:white;background:#3A69C2;text-decoration:none">MULTIPLY
</span></a><o:p></o:p></span></b></p>
</td>
<td style="padding:0in 0in 0in 0in">
<p class="MsoNormal"><span style="font-size:12.0pt;font-family:"Times New Roman",serif"> <o:p></o:p></span></p>
</td>
<td width="20%" style="width:20.0%;background:#3A69C2;padding:4.5pt 4.5pt 4.5pt 4.5pt;display:inline-block">
<p class="MsoNormal" align="center" style="text-align:center"><b><span style="font-size:11.5pt;font-family:"Helvetica",sans-serif;color:white"><a href="mailto:test.com?subject=[DIVIDE];body=ACTION:%20DIVIDE"><span style="color:white;background:#3A69C2;text-decoration:none">DIVIDE
</span></a><o:p></o:p></span></b></p>
</td>
<td style="padding:0in 0in 0in 0in">
<p class="MsoNormal"><span style="font-size:12.0pt;font-family:"Times New Roman",serif"> <o:p></o:p></span></p>
</td>
</tr>
</tbody>
</table>
Could you use the Id attribute of the html tags https://www.w3schools.com/tags/att_id.asp to identify the tags that you want to remove ?
Assuming you want to remove the table containing the Multiply and Divide buttons and that they will not be found anywhere else in the document we can use those in combination with XPath to find the table and remove it. You could possible use the inbuild XMLDocument class but as this it HTML I'll recommend using HTMLAgilityPack (available as a nuget package) to parse the HTML.
You'll end up with something like:
//Create a HTMLAgilityPack Document
HtmlDocument doc = new HtmlDocument();
//Load the email body
doc.LoadHtml(EmailMessage.Body.Text);
//Select the ancestor table of the link we're interested in
HtmlNode node = doc.DocumentNode.SelectSingleNode("//a[#href='mailto:test.com?subject=[DIVIDE];body=ACTION:%20DIVIDE']//ancestor::table");
//Remove the table
node.Remove();
//Get the new email body
string newBody = doc.DocumentNode.InnerHtml;
You may need to tweak a little to get you there but hopefully this is a good start.

HtmlAgilityPack adding nodes to other nodes

I am using HtmlAgilityPack to parse my html. My main goal is add some div elements around table row elements. However there are also some more elements in the table row. I only want to wrap it with div elements when the font's style is a background color of lightgreen.
Here's an example of what my html looks like:
<tr>
<td style="padding-left: 40pt;"><font style="background-color: lightgreen" color="black">Tove</font></td>
<td style="padding-left: 40pt;"><font style="background-color: lightgreen" color="black">To</font></td>
</tr>
however my current code:
HtmlNode[] nodes = document.DocumentNode.SelectNodes("//tr[//td[//font[#style='background-color: lightgreen']]]").ToArray();
foreach (HtmlNode node in nodes)
{
node.InnerHtml = node.InnerHtml.Replace( node.InnerHtml,"<div class=\"select-me\">" +node.InnerHtml + "</div>");
}
produces this html:
<tr>
<div class="select-me">
<td style="padding-left: 25pt;"><font style="background-color: white" color="black"><to</font><font style="background-color: white" color="black">></font></td>
<td style="padding-left: 25pt;"><font style="background-color: white" color="black"><to</font><font style="background-color: white" color="black">></font></td>
</div>
</tr>
<tr>
<div class="select-me">
<td style="padding-left: 40pt;"><font style="background-color: lightgreen" color="black">Tove</font></td>
<td style="padding-left: 40pt;"><font style="background-color: lightgreen" color="black">To</font></td>
</div>
</tr>
<tr>
<div class="select-me">
<td style="padding-left: 25pt;"><font style="background-color: white" color="black"></to></font></td>
<td style="padding-left: 25pt;"><font style="background-color: white" color="black"></to></font></td>
</div>
</tr>
the div elements don't surround the tr elements and every tr has a div element, when only a tr element that has font element of background color lightgreen should contain a div element. If you look at the first tr element it has 4 font elements, instead of two. Ideally, my goal is to insert div elements around a tr element when its font's element background is lightgreen. I have looked at other posts, but I am still having trouble.
Correct html should like:
<div class="select-me">
<tr>
<td style="padding-left: 25pt;"><font style="background-color: lightgreen" color="black">hello</font></td>
<td style="padding-left: 25pt;"><font style="background-color: lightgreen" color="black">goodbye</font></td>
</tr>
</div>
for (var i = 0; i < nodes.Length; i++ )
{
var node = nodes[i];
node = HtmlNode.CreateNode(node.OuterHtml.Replace(node.OuterHtml, "<div class=\"select-me\">" + node.OuterHtml + "</div>"));
}

HtmlAgilityPack to get data from HTML table in C#

Using HtmlAgilityPack, how to get data from input hidden values and tr, td rate in C# from HTML table?
I need to input hidden values to tr, td rate. How to get that information my below html table?
<table>
<caption>
<div id="cal_nav"
class="float_right">
<ul class="inline">
<li>
<a href="#"
onClick="changeRatesView('calendar')">Calendar View</a>
</li>
<li id="previous"
class="first">
<a title="September"
- "2015"
href="#"
onClick="searchPrevMonthAvailability()"> </a>
</li>
</div>
</caption>
<thead>
<tr>
<th>Date</th>
<th>Occupancy</th>
<th>Net Rate</th>
<th>Sell Rate</th>
</tr>
</thead>
<tbody>
<input type="hidden"
name="rateid"
value="234154166">
<tr>
<td>1</td>
<td>single</td>
<td>1652</td>
<td>2500</td>
</tr>
<tr>
<td>2</td>
<td>single</td>
<td>1454</td>
<td>4344</td>
</tr>
<input type="hidden"
name="rateid"
value="234154134">
<tr>
<td>1</td>
<td>single</td>
<td>1652</td>
<td>2500</td>
</tr>
<tr>
<td>2</td>
<td>single</td>
<td>1454</td>
<td>4344</td>
</tr>
<input type="hidden"
name="rateid"
value="234154145">
<tr>
<td>1</td>
<td>single</td>
<td>1652</td>
<td>2500</td>
</tr>
<tr>
<td>2</td>
<td>single</td>
<td>1454</td>
<td>4344</td>
</tr>
</tbody>
</table>
MY Linq code:
var tds= (from td in doc.DocumentNode.Descendants("table")
select td).ToList()[2].ChildNodes[2];
var trer = tdsyh.SelectNodes("//input[#type='hidden' and #name='rateid']|tr").Select(x => x).ToList();
You can try something like:
var hiddenFields = doc.DocumentNode.Descendants("input").Where(_ => _.GetAttributeValue("type", "").Equals("hidden") && _.Name.Equals("rateid"));

Failing to retrieve the third td nodes in an html list

I am trying to get the text "Very Good Country views" and "Good" using HTMLAgilityPack.
<div class="property-details-section">
<h5><span id="content_lblFurtherDetails">Further Details</span></h5>
<ul id="features">
<li style="display:block;">
<table border="0" cellpadding="0" cellspacing="0" width="500">
<tr>
<td style="width: 15px;">
<img src="../images/bullet.png" alt="bullet" />
</td>
<td style="width: 185px;">Views</td>
<td style="width: 300px;">Very Good Country views</td>
</tr>
</table>
</li>
</ul>
<li style="display:block;">
<table border="0" cellpadding="0" cellspacing="0" width="500">
<tr>
<td style="width: 15px;">
<img src="../images/bullet.png" alt="bullet" />
</td>
<td style="width: 185px;">Finish</td>
<td style="width: 300px;">Good</td>
<tr>
</table>
</li>
</div>
I have tried the following for "Very Good Country views" with no success:
HtmlNode text =
doc.DocumentNode.SelectSingleNode("//ul[#id='features']/li/table/tr/td[3]");
I am trying to get the text "Very Good Country views" and "Good"
You have to select 2 elements, so you should use SelectNodes instead of SelectSingleNode, if you want get the result at once.
var result = doc.DocumentNode.SelectNodes("//ul[#id='features']/li/*//td[last()]")
.Select(td => td.InnerText)
.ToList();
I think the problem about your XPath is that you should add brackets around the expression:
var text = doc.DocumentNode
.SelectSingleNode("(//ul[#id='features']/li/table/tr/td)[3]");
You can also try using LINQ:
var td = doc.Descendants("ul")
.First(x => x.GetAttributeValue("id","") == "features")
.Descendants("td")
.Skip(2)
.First();
var text = td.InnerText;

Categories