I have a string of html returning from a serivce. I need to update this html server side (Using .Net) and reorder some of the elements around before sending it to the client. As a simple example lets say I have an html string like below. If the string is a table like below. How can I manipulate it to put the last name <th> and <td> into it's own <tr>. The html would be much larger and more complex but for one section of it the below illustrate how I would need to change it. Just using string replace hasn't worked well due to the complexity of the actual HTML.
Initial String
"<table>
<tbody>
<tr>
<th>First name</th>
<td>some first name</td>
<th>Last name</th>
<td>some last name</td>
</tr>
<tr>
<th>blah</td>
<td>blah blah</td>
</tr>
</tbody>
</table>
"
After Modification
"<table>
<tbody>
<tr>
<th>First name</th>
<td>some first name</td>
</tr>
<th>Last name</th>
<td>some last name</td>
<tr>
<th>blah</td>
<td>blah blah</td>
</tr>
</tbody>
</table>
"
I know URL answers are frowned upon, but you should look into the HTML Agility Pack. It's designed for this kind of thing.
http://html-agility-pack.net/?z=codeplex
For the purposes of this answer, I will make the silly assumption that you have read the file in a string list. Let us name this list HTMLLines. Then the following should do what you want
int length=HTMLLines.Count;
for(int loop=0;loop<length;loop++)
{
if(HTMLLines[loop].Equals("<th>Last name</th>"))
{
HTMLLines[loop]="</tr>\n<tr>\n"+HTMLLines[loop];
//break;//If there is only one occurrence, remove the leading // else keep that to repeat for each occurence
}
}
If you save the list after this loop, you should have the desired output.
This code assumes that there are no nulls in the list. If there are any nulls, you should replace HTMLLines[loop].Equals("<th>Last name</th>") with HTMLLines[loop]=="<th>Last name</th>"
If the "<th>Last name</th>" is just a sample you used for this question that cannot be used to match exactly, then you should place all possible matches to an array and check for them each loop. In this case, if we name the array theHeaders, the code will be something like:
int length=HTMLLines.Count;
for(int loop=0;loop<length;loop++)
{
for(int loop1=0;loop1<theHeaders.Length;loop1++)
{
if(HTMLLines[loop].Equals(theHeaders[loop1]))
{
HTMLLines[loop]="</tr>\n<tr>\n"+HTMLLines[loop];
break;
}
}
}
I hope this helps to point you to the right direction.
A very simple approach could be...
var result = htmlString.Replace("<th>Last name</th>", "</tr><tr><th>Last name</th>");
If you need something more complex than this you'll need to add more detail to your question.
Related
<table class ="table" cellpadding="0" cellspacing="0">
<tr>
<th>Item Name</th>
<th>Price</th>
<th>Seafood</th>
<th>Has Gluten</th>
<th>Picture</th>
</tr>
#foreach (var items in #Model)
{
<tr>
<td>#items.ItemName</td>
<td>#items.Price</td>
<td>#items.IsSeafood</td>
<td>#items.HasGluten</td>
</tr>
}
I am currently learning how to develop using ASP.NET MVC.
I am trying to insert different images for each of my items. My foreach loop creates the table and items from a mysql database. I want to add the pictures next to the tables unless I'm unable to with the code I have.
You can use an <img src=""/> tag inside your last <td> to embed the image directly into the html.
Something like this, depending on how your image is stored.
<td><img src="#items.Url"/></td>
I have nested 3 lists. And I want those data to display in a table. When I'm trying like this,
<tbody>
<tr ng-repeat-start="item in searchResultList" >
<td>{{item.Group.AuditDate | date:"MM/dd/yyyy h:mma"}}</td>
<td>{{item.Group.User}}</td>
</tr>
<tr ng-repeat-start="x in item.DeviceList.DescriptionList">
<td></td>
<td></td>
<td>{{x.Description}}</td>
</tr>
<tr ng-repeat-end ng-repeat="y in x.ChangesList">
<td></td>
<td></td>
<td></td>
<td>{{y.ChangeFrom}}</td>
<td>{{y.ChangeTo}}</td>
</tr>
<tr ng-repeat-end></tr>
</tbody>
Then It displays like this.
But I don't want to repeat lines when each data repeat. I want to display all the 1st data in a straight line,and when description repeat for the same date and user, then it should be in a new line. I want an alignment like this.
Parse your data in below format in the controller and then use ng-repeat to display.
[{'08/11/2016 5:56PM', 'Administrator','Aaa','b','c'}, {'', '','','d','f'},{'','','Bbb','b','c'},{'10/16/2015 11:41AM','Tharuka','Ccc','c','d'}]
How can I count the href attributes of my HTML?
<table>
<tbody>
<tr>
<td align="right" colspan="8">
2
3
4
</td>
</tr>
</tbody>
</table>
Get the elements by tagname and het the size of the result:
driver.findElements(By.xpath("//a[#href]")).size()
Whilst I generally avoid XPath, this seems like the time to use it.
If you are simply trying to get the number of links on a page without having to filter on specific links, you can do this in C# by:
int linkCount = _driver.FindElements(By.XPath("//a")).Count;
You can then Assert on that number returned (to actually do a test on this, if you don't assert, the test will always pass). If you want to filter on specific links I would use something other than XPath.
I have an html table I need to query, get the contents and then act on that.
this the table
<table>
<thead>
<tr>
<th>Version</th>
<th>Usage</th>
</tr>
</thead>
<tbody>
<tr>
<td>1.0.1.1</td>
<td>86</td>
</tr>
<tr>
<td>1.0.0.1</td>
<td>65</td>
</tr>
<tr>
<td>1.0.1.0</td>
<td>28</td>
</tr>
<tr>
<td>1.0.0.0</td>
<td>1</td>
</tr>
</tbody>
</table>
I'm getting that by passing the WebResponse through a regex expression.
What is the best way to get this into some data structure in C# so that I can query on the Version and Usage.. Baically have a List of class Foo.
Foo()
{
Version {get; set;}
Usage {get; set;}
}
Along those lines.
Thanks for your help
The best tool I've found for parsing HTML is the Html Agility Pack library. It is a fairly easy to use library, and will handle improperly formatted markup fairly well. You'll have to do the footwork of getting the data out from the library and into your own structures, but it'll make it easy for getting at the data.
I am on the server side of an asp.net application. There I have some html source code in a variable called 'HtmlText'. This source code is generated from xml via a xsl transformation, and is resulting in something like this:
<h1>ABC Test KH</h1>
<!--place for the control-->
<table class="tablesorter" id="tablesorter183">
<thead>
<tr>
<th align="left">Name</th>
<th align="right">DB</th>
<th align="right">DB Anteil in Prozent</th>
<th align="right">ABC</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left" fieldName="Name">Fabrikam, Inc.</td>
<td align="right" fieldName="DB">881.378,00 €</td>
<td align="right" fieldName="DB_Anteil_in_Prozent">29,92</td>
<td align="right" fieldName="ABC">A</td>
</tr>
</tbody>
</table>
Now this source code is inserted in a aspx-website via the InnerHtml-property.
There is a div with id 'book' in that aspx:
book.InnerHtml = HtmlText
This works fine so far.
But now I want to create a dropdown-control in that html, which I can access on server-side. This control should be placed between the h1 and table-tags, where the comment <!--place for the control--> is located.
I know how to create asp-control dynamically and bind an event to that, but this works only if I have the aspx in the first place. I cannot do that to some html-source which exists just in a string at that time.
Is there any way to do what I want, or am I on the wrong track here?
Thanks in advance for any suggestions.
Kind regards,
Kai
I think the only solution is to create a control that inherits DropDownList, and override its RenderControl method.
Something like this:
public override void RenderControl(HtmlTextWriter writer)
{
//...
//Fill in the variable HtmlText content
//Split it to 2 variables - before and after the control place, and:
writer.Write(startString);
base.RenderControl(writer);
writer.Write(endString);
}
And use this control instead of DropDownList.
EDIT: In a case of several controls, I would use the way suggested here: Render .net controls to string and get events to fire:
Split the string to several strings - the first string - from the beginning to the first control, second string - from the first control to the second control, and so on.
And then insert each of the strings to a new LiteralControl, and add them to the page Like this:
book.Controls.Add(LiteralControl1);
book.Controls.Add(DropDownList1);
book.Controls.Add(LiteralControl2);
book.Controls.Add(Button1);