Cannot find table using c# - c#

I trying to change value of a particular cell in a table, but i am getting an error, can anyone see what the problem is please :
Test WebTable.IWebTableTests.testIWebTableTests failed: System.NullReferenceException : Object reference not set to an instance of an object.
WebTableTests.cs(37,0): at WebTable.IWebTableTests.testIWebTableTests()
<div class="cart-info">
<table border="1">
<thead>
<tr>
<td class="name">Product Name</td>
<td class="model">Model</td>
<td class="quantity">Quantity</td>
<td class="price">Unit Price</td>
<td class="total">Total</td>
</tr>
</thead>
<tbody>
</table>
</div>
and:
IWebElement table = driver.FindElement(By.CssSelector(".cart-info>table"));
ReadOnlyCollection<IWebElement> allRows = table.FindElements(By.TagName("tr"));
ReadOnlyCollection<IWebElement> allCols = table.FindElements(By.TagName("td"));
//Verify that it has three rows
Assert.AreEqual(3, allRows.Count);
//Verify that it has six columns
Assert.AreEqual(5, allCols.Count);
//Verify that specified value exists in second cell of third row
Assert.AreEqual("iPhone", allRows[3].FindElements(By.TagName("td"))[1].Text);
//Get in cell editor and enter some value
string cellValue = allRows[3].FindElements(By.TagName("td"))[3].Text;
IWebElement cellEdit = allRows[3].FindElements(By.TagName("td"))[3];
cellEdit.Clear();
cellEdit.SendKeys("2");
string aftercellValue = allRows[3].FindElements(By.TagName("td"))[3].Text;

Related

How to Retrieve Specific table from HTML FILE in c#?

I have an HTML file that contains many tables, but I want to access a specific table from the file (not all tables).
So how can I do that?
Code is look something like below and all tables are without ids
`<table border=1>
<tr><td>VI not loadable</td><td>0</td></tr>
<tr><td>Test not loadable</td><td>0</td></tr>
<tr><td>Test not runnable</td><td>0</td></tr>
<tr><td>Test error out</td><td>0</td></tr>
</table>`
every table should have an Id or something that could be Identified from the others, if so you can get it via jquery. for example :
<table class="table table-striped" id="tbl1">
<thead>
<tr>
<th>Firstname</th>
<th>Lastname</th>
<th>Email</th>
</tr>
</thead>
<tbody>
<tr>
<td>John</td>
<td>Doe</td>
<td>john#example.com</td>
</tr>
<tr>
<td>Mary</td>
<td>Moe</td>
<td>mary#example.com</td>
</tr>
<tr>
<td>July</td>
<td>Dooley</td>
<td>july#example.com</td>
</tr>
</tbody>
and get it like this:
var table = $('#tbl1').html();
if not you can find it by its priority in the file. for example you can access to 2nd table like this :
var table = $('table:nth-child(2)')
or in C# maybe this would help:
HtmlNode table = doc.DocumentNode.SelectSingleNode("//table[1]")
foreach (var cell in table.SelectNodes(".//tr/td"))
{
string someVariable = cell.InnerText
}

Faster Approach to Find Parent Child Relationship

I have a product structure table like the following:
<table>
<tr>
<td>Parent</td>
<td>Component</td>
<td>Quantity</td>
</tr>
<tr>
<td>123100A</td>
<td>123201B</td>
<td>1</td>
</tr>
<tr>
<td>123201B</td>
<td>123301A</td>
<td>1</td>
</tr>
<tr>
<td>123201B</td>
<td>123302A</td>
<td>1</td>
</tr>
<tr>
<td>123301A</td>
<td>123401A</td>
<td>1</td>
</tr>
<tr>
<td>123301A</td>
<td>123402A</td>
<td>1</td>
</tr>
<tr>
<td>123301A</td>
<td>123403A</td>
<td>1</td>
</tr>
</table>
Currently, I populate a list with my product structure and recursively loop through it to get all the base level components of a finished good item. The finished good item would be 123100A, or any parent that doesn't show up as a component in the list. In the end, I get a list that looks like this:
<table>
<tr>
<td>Parent</td>
<td>Component</td>
<td>Quantity</td>
</tr>
<tr>
<td>123100A</td>
<td>123302A</td>
<td>1</td>
</tr>
<tr>
<td>123100A</td>
<td>123401A</td>
<td>1</td>
</tr>
<tr>
<td>123100A</td>
<td>123402A</td>
<td>1</td>
</tr>
<tr>
<td>123100A</td>
<td>123403A</td>
<td>1</td>
</tr>
</table>
Here is the code I use to recursively loop to find each end component:
public void getCapacityComponents(string parPart, string partNum, decimal qtyMultiplier)
{
//Start of recursion to get child items
List<ProductStructure> capacity = new List<ProductStructure>();
var result = from x in psList
join y in partsList on x.parent equals y.part
where x.parent == partNum
select x;
//recursive loop through components
foreach (var x in result)
{
ProductStructure mrpProduct = new ProductStructure();
mrpProduct.parent = x.parent;
mrpProduct.component = x.component;
if (x.quantity == 0)
mrpProduct.quantity = qtyMultiplier;
else
mrpProduct.quantity = x.quantity * qtyMultiplier;
capacity.Add(mrpProduct);
}
if (capacity.Count > 0)
{
foreach (var part in capacity)
{
getCapacityComponents(parPart, part.component, part.quantity);
}
}
else
{
ProductStructure capacityPart = new ProductStructure();
capacityPart.parent = parPart;
capacityPart.component = partNum;
capacityPart.quantity = qtyMultiplier;
mrpProductList.Add(capacityPart);
}
//End of current solution to get child items
}
I send this function a list of finished good parts and use the MRPProductList to compare the components to all finished goods. I get the result I want but this takes a very long time to run. I usually have around 2700 Finished good parts that I need to loop through to get all end component items.
Is there a more efficient way to go through a list to find these items without doing the recursive loop?

htmlAgilityPack parse table to datatable or array

I have these tables:
<table>
<tbody>
<tr><th>Header 1</th></tr>
</tbody>
</table>
<table>
<tbody>
<tr>
<th>Header 1</th>
<th>Header 2</th>
<th>Header 3</th>
<th>Header 4</th>
<th>Header 5</th>
</tr>
<tr>
<td>text 1</td>
<td>text 2</td>
<td>text 3</td>
<td>text 4</td>
<td>text 5</td>
</tr>
</tbody>
</table>
I am trying to transform into an array or List using this code:
var query = from table in doc.DocumentNode.SelectNodes("//table").Cast<HtmlNode>()
from row in table.SelectNodes("tr").Cast<HtmlNode>()
from header in row.SelectNodes("th").Cast<HtmlNode>()
from cell in row.SelectNodes("td").Cast<HtmlNode>()
select new {
Table = table.Id,
Row = row.InnerText,
Header = header.InnerText,
CellText = cell.InnerText
};
But it doesn't work. What is wrong?
Some notes:
You do not need a cast
you are assuming that each row have headers
SelectNodes needs to receive an xpath and you are passing just names
if i were you i would use a foreach and model my data, that way i get to have more control and efficiency, but if you still want to do it your way this is how it should be
var query = from table in doc.DocumentNode.SelectNodes("//table")
where table.Descendants("tr").Count() > 1 //make sure there are rows other than header row
from row in table.SelectNodes(".//tr[position()>1]") //skip the header row
from cell in row.SelectNodes("./td")
from header in table.SelectNodes(".//tr[1]/th") //select the header row cells which is the first tr
select new
{
Table = table.Id,
Row = row.InnerText,
Header = header.InnerText,
CellText = cell.InnerText
};

How to get next 2 nodes in HTML + HTMLAgilitypack

I have a table in the HTML code below:
<table style="padding: 0px; border-collapse: collapse;">
<tr>
<td><h3>My Regional Financial Office</h3></td>
</tr>
<tr>
<td> </td>
</tr>
<tr>
<td><h3>My Address</h3></td>
</tr>
<tr>
<td>000 Test Ave S Ste 000</td>
</tr>
<tr>
<td>Golden Valley, MN 00000</td>
</tr>
<tr>
<td>Get Directions</td>
</tr>
<tr>
<td> </td>
</tr>
</table>
How can I get the inner text of the next 2 <tr> tags after the tablerow containing the text "My Address?"
You can use following XPath :
var htmlDoc = new HtmlDocument();
htmlDoc.LoadHtml(html);
var tdOfInterests =
htmlDoc.DocumentNode
.SelectNodes("//tr[td/h3[.='My Address']]/following-sibling::tr[position() <= 2]/td");
foreach (HtmlNode td in tdOfInterests)
{
//given html input in question following code will print following 2 lines:
//000 Test Ave S Ste 000
//Golden Valley, MN 00000
Console.WriteLine(td.InnerText);
}
The key of above XPath is using following-sibling with position() filter.
UPDATE :
A bit explanation about the XPath used in this answer :
//tr[td/h3[.='My Address']]
above part select <tr> element that has :
child <td> element that has child <h3> element with value equals
'My Address'
/following-sibling::tr[position() <= 2]
next part select following <tr> element with position <=2 from current <tr> element (the one selected by previous XPath part)
/td
the last part select child <td> element from current <tr> element

get a specific row from the html with a specific word using regular expression

I want to fetch all rows having a specific word/string in its.. and store it in array
I have a string as below
<tr>
<td>Total</td>
<td>123</td>
<td>567</td>
</tr>
<tr>
<td>ABC</td>
<td>123</td>
<td>567</td>
</tr>
<tr>
<td>XYZ</td>
<td>123</td>
<td>567</td>
</tr>
<tr>
<td>Total</td>
<td>7676</td>
<td>8767</td>
</tr>
I want to fetch a row having the string Total and the value of should store in array
So output should
<tr>
<td>Total</td>
<td>123</td>
<td>567</td>
</tr>
<tr>
<td>Total</td>
<td>7676</td>
<td>8767</td>
</tr>
what should be the regular expression to fetch a row with a string "Total"
To build arrays for each table row that has a cell with the word "Total", you could use this regex:
(?<=<tr>\s*<td>Total</td>)(\s*<td>\d+</td>)+(?=\s*</tr>)
Which would give you the following 2 matches:
<td>123</td>
<td>567</td>
and
<td>7676</td>
<td>8767</td>
On these matches you could then split with this regex to get arrays in return:
\D+
IN JQUERY UR SOLUTION WILL--->
var tbl = $('#tblId')
var array = [];
$('tr td' ,tbl).each(function(){
var htmlstring = (this).innerHTML;
if(htmlstring == 'Total')
{
if((this).innerHTML == 'Total')
{
$('td', this.parentNode).each(function(){
array.push(this);
});
}
}
});
alert(array);
http://jsfiddle.net/gXGj6/13/
Good solution using jQuery:
http://jsfiddle.net/robfarmer/KaGBL/2/
HTML:
Source
<table id="source">
<tr>
<td>Total</td>
<td>123</td>
<td>567</td>
</tr>
<tr>
<td>ABC</td>
<td>123</td>
<td>567</td>
</tr>
<tr>
<td>XYZ</td>
<td>123</td>
<td>567</td>
</tr>
<tr>
<td>Total</td>
<td>7676</td>
<td>8767</td>
</tr>
</table>
Results
<table id="results"></table>
Array Results:
<ul id="arrayResults"/>
Javascript
$(document).ready(function() {
$("#source tr td:contains('Total')").closest("tr").clone().appendTo("#results");
var cells = [];
$("#source tr td:contains('Total')").closest("tr")
.children("td").not(":contains('Total')").each(function(index, element) {
cells.push($(element).text());
});
$(cells).each(function(index, element) {
$("#arrayResults").append($("<li>").text(element));
});
});

Categories