C# - Extract speciifc div class text using HTMLAgility - c#

I have a code in C# where I want to extract the below value (the text "I want this text" in the HTML code below). I have reformat the HTML code to make it easily readable.
<div class="paste-copy-url" style="margin:0 0 0 0;">
<h4>My Stats:</h4>
<div class="line">
<div class="wrap-input">
<input onclick="this.select();" value="I want this text" readonly="readonly">
</div>
</div>
<h4>Website Link:</h4>
<div class="line">
<div class="wrap-input"><input onclick="this.select();" value="Some value" readonly="readonly">
</div>
</div>
</div>
The code I tried (It is giving me the text : "Website Link:"):
var myvaluetoextract = htmlDocument.DocumentNode.SelectSingleNode("//div[#class='paste-copy-url']");
What am I doing wrong? Can I use this approach to get that element (There is only 1 instance of the div class in the page)?

var input = htmlDocument.DocumentNode
.SelectSingleNode("//div[#class='paste-copy-url']//div[#class='wrap-input']/input");
var yourText = input.Attributes["value"].Value;

You can do it like this:
var myvaluetoextract = htmlDocument.DocumentNode.SelectSingleNode("//div[#class='paste-copy-url']//input");
var value = myvaluetoextract.GetAttributeValue("value", null);
//input means you search for input elements in the div's subtree, recursively. GetAttributeValue is a helper that will never fail, even if the attribute doesn't exists (in this case if will return the 2nd passed parameter - which is null here)

Related

Identify XPath from particular element

I'm working on a page, where page loads dynamically and the data gets added while scrolling. To identify the properties of an item, I identified the parent div, where to identify the address, I have to locate an XPath from the parent to span element.
Below is my DOM structure:
<div class = "parentdiv">
<div class = "search">
<div class="header">
<div class="data"></div>
<div class="address-data">
<div class="address" itemprop="address">
<a itemprop="url" href="/search/Los-Angeles-CA-90025">
<span itemprop="streetAddress">
Avenue
</span>
<br>
<span itemprop="Locality">Los Angeles</span>
<span itemprop="Region">CA</span>
</a>
</div>
</div>
</div>
</div>
</div>
</div>
Here I want to locate the three spans, where I' currently in parent div.
Can someone guide how to locate an element using XPath from particular div?
You can try the following XPaths,
To locate the street address:
//div[#class="parentdiv"]/div/div/a/span[#itemprop="streetAddress"]
To locate the locality/city:
//div[#class="parentdiv"]/div/div/a/span[#itemprop="Locality"]
To locate the state:
//div[#class="parentdiv"]/div/div/a/span[#itemprop="Region"]
To print the list of <span> tagged WebElements with texts like Avenue with respect to div class = "parentdiv" node you can use the following block of code :
IList<IWebElement> myList = Driver.FindElements(By.CssSelector("div.parentdiv > div.address > a[itemprop=url] > span"));
foreach (IWebElement element in myList)
{
string my_add = element.GetAttribute("innerHTML");
Console.WriteLine(my_add);
}
Your DOM might become fairly large, since it adds elements while scrolling, so using CSS selectors might be quicker.
To get all the span tags in the div, use:
div[class='address'] span
To get a specific span by using the itemprop attribute use:
div[class='address'] span[itemprop='streetAddress']
div[class='address'] span[itemprop='Locality']
div[class='address'] span[itemprop='Region']
You can store the elements in a variable like so:
var streetAddress = driver.FindElement(By.CssSelector("div[class='address'] span[itemprop='streetAddress']"));
var locality = driver.FindElement(By.CssSelector("div[class='address'] span[itemprop='Locality']"));
var region = driver.FindElement(By.CssSelector("div[class='address'] span[itemprop='Region']"));

How to append a C# formatted html

I have a button that append's the same layout of html but I have a problem taking the select values with it. My html is:
<div id="degreePlusSign">Button</div>
<div class="padding">
<div class="col-md-5 col-xs-12">
<label for="prefix" class="sr-only">Degrees</label>
<select class="form-control marginBottom15">
#{
foreach (var degree in ViewBag.NewDegrees)
{
<option value="#degree.DegreeID" selected>#degree.DegreeName</option>
}
}
</select>
<span class="glyphicon form-control-feedback"></span>
</div>
</div>
JS:
$('#degreePlusSign').on('click', function () {
$(this).closest('.padding').append('<div class="padding mBottom"><i class="fa fa-times-circle fa-2x" aria-hidden="true"></i><div class="col-md-5 col-xs-12"><select class="form-control marginBottom15">#{foreach (var degree in ViewBag.NewDegrees){<option value="#degree.DegreeID" selected>#degree.DegreeName</option>}}</select><span class="glyphicon form-control-feedback"></span></div><div class="col-md-7 col-xs-12"><input class="form-control" placeholder="Major/Area of Study" type="text" /></div></div>');
});
Basically it recreates the html, but my problem is I'm using a foreach loop to bring in the values from the backend and it will only work with the inital container, not the duplicated containers afterwards. How do I keep the values on every duplication with the append jquery?
You have got two options:
Spit options values (formatted) from C# and keep in a JS variable:
{
var opts=new StringBuilder();
var sel="selected";
foreach(var d in ViewBag.NewDegrees)
{
opts.Append($"{d.DegreeName}");
sel="";
}
}
Then somewhere down store it into a js variable:
var optsList="#(opts)";
Now you can use append new HTML as:
$('#degreePlusSign').on('click', function () {
$(this).closest('.padding').append('<div class="padding mBottom"><i class="fa fa-times-circle fa-2x" aria-hidden="true"></i><div class="col-md-5 col-xs-12"><select class="form-control marginBottom15">'+
optsList/*THIS IS THE VALUE WE STORED FROM C# CODE*/
+'</select><span class="glyphicon form-control-feedback"></span></div><div class="col-md-7 col-xs-12"><input class="form-control" placeholder="Major/Area of Study" type="text" /></div></div>');
});
Clone the generated select element and use that:
$('#degreePlusSign').on('click', function () {
/*CLONE EXISTING SELECT ELEMENT. YOU MAY WANT TO PUT AN ID FOR SELECTION*/
var cl=$("select.form-control.marginBottom15").clone();
var d = $("").addClass("padding mBottom")
append("").addClass("fa fa-times-circle fa-2x").attr("aria-hidden",'true');
/*APPEND CLONED SELECT TO INNER DIV*/
d.append("").addClass("col-md-5 col-xs-12").append(cl);
d.append(cl);
d.append("").addClass(glyphicon form-control-feedback");
d.append("").addClass("col-md-7 col-xs-12").append("").addClass("form-control")
.attr("placeholder","Major/Area of Study").attr("type","text");
$(this).closest(".padding").append(d);
});`
Hope you will be able fix any jQuery mess. I haven't used it since long.
.clone was what I was looking for. $('.padding').clone().append('.padding');

Selenium webdriver get value from data-bind on span tag

I need to get the value from this tag
<span>
<a class="jsk-sa-dialog link-lightbox-valores" data-bind="attr: { href: '#sa-valor-' + $root.types().id }" href="#sa-valor-2">
Link to click that pop-ups a new window
</a>
</span>
After look at the "html" code in debugger, I saw the text that I want to get into HTML...
To get the text that is generated into the popup window, I wrote this code:
case "someBaseText":
{
details.Click(); // Simulate the click on <a> tag
var tx = details.FindElement(By.XPath("//div[#class='overview-material']"));
var dv = tx.FindElement(By.XPath("//div[#class='sa-valor']/h3"));
var ttText = dv.Text; // Empty :(
}
The HTML that i got from debugger:
<div class="overview-material">
<div class="valores" data-bind="foreach: $root.types">
<div class="sa-valor" data-bind="attr: { id: 'sa-valor-' + id }" id="sa-valor-2">
<h3 class="titulo">Mensalidade</h3>
<div class="texto" data-bind="html: apresentacao.valor">
TEXT TEXT TEXT TEXT TEXT TEXT TEXT TEXT TEXT
So, I want to get the text inside of div class "texto"
Based on the XPath of dv, you are getting the <h3> element:
<h3 class="titulo">Mensalidade</h3>
therefore dv.Text should return "Mensalidade".
Try updating your XPath to the <div> with class='texto':
//div[#class='sa-valor']/div[#class='texto']
Try CssSelector:
var text = driver.FindElement(By.CssSelector("div.texto")).Text;

Show specific section of HTML in textbox

I want to show a specific section of a html-page in a textbox in a WP7-app (C#). After a bit of searching online I found this:
HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
doc.LoadHtml("http://www.positief-project.be/?p=532");
string links = doc.DocumentNode
.Descendants("section")
.Where(section => section.Attributes["class"] != null &&
section.Attributes["class"].Value == "article-content").ToString();
txbContent.Text = links;
This doesn't give an error, but doesn't work either. How can I make it show in the text box?
Is jQuery an option?
HTML
<div class="section">
<div class="article-content">some foo 1</div>
<div class="article-content">some foo 2</div>
<div class="article-content">some foo 3</div>
<div class="article-content">some foo 4</div>
</div>
<br>
<input type="text" id="tbContent" />
jQuery
$(document).ready(function () {
var content;
$('.article-content').each(function(i, obj){
content += obj.innerHTML;
});
$('#tbContent').val(content);
});
See this fiddle http://jsfiddle.net/rodhartzell/Fk2xM/

How can I pass a value from my page to the controller?

I'm using MVC with Razor and C#. I would like to update an element... a counter with ajax. Here is my code:
#model Domain.CounterObject
#using (Ajax.BeginForm("Count", "CounterObject", new AjaxOptions { HttpMethod = "POST", UpdateTargetId = "my-control" }))
{
<div id="my-control" class="bid-object">
<div>
<span class="title">#Html.Encode(Model.Title)</span>
</div>
<div>
<span class="display">#Html.Encode(Model.GetFinalDate())</span>
</div>
<div>
<span class="display">#Html.Encode(Model.GetValue())</span>
</div>
<div>
<input type="submit" value="Count" />
</div>
</div>
}
In my controller I have this code:
[HttpPost]
public PartialViewResult Count(CounterObject counter)
{
// Special work here
return PartialView(counter);
}
The problem is that my CounterObject counter I receive in my Count method is always null. How can I pass a value from my page to the controller?
I receive in my Count method is always null
First of all you are not submitting anything from the form then how does the binding happens?
If the user is not allowed to edit the values but still you want to submit them through the form then you have to use hidden fields along with them.
For ex.
<div>
<span class="title">#Html.Encode(Model.Title)</span>
#Html.HiddenFor(m => m.Title)
</div>
Note that the hidden fields should have the same names as the properties to make the binding happen successfully.
It is better to have properties in the Model that store the GetFinalDate() and GetValue() results so you can easily bind the things like in Title.
You'll have to define a input field with a name and id that the ModelBinder can then Bind to your CounterObject.
You could use #Html.EditorForModel once and then inspect the generated Html to see what kind of name/id pairs it is generating. With those you can go on and handcraft your Html if you wanted to.
use
<span class="title">#Html.Encode(Model.Title)</span>
<div class="editor-field">#Html.EditorFor(Model => Model.Title)<div>
//For other fields
In this way you can bind to your object.

Categories

Resources