19

So I have an HTML snippet that I want to modify using C#.

<div>
This is a specialSearchWord that I want to link to
<img src="anImage.jpg" />
<a href="foo.htm">A hyperlink</a>
Some more text and that specialSearchWord again.
</div>

and I want to transform it to this:

<div>
This is a <a class="special" href="http://mysite.com/search/specialSearchWord">specialSearchWord</a> that I want to link to
<img src="anImage.jpg" />
<a href="foo.htm">A hyperlink</a>
Some more text and that <a class="special" href="http://mysite.com/search/specialSearchWord">specialSearchWord</a> again.
</div>

I'm going to use HTML Agility Pack based on the many recommendations here, but I don't know where I'm going. In particular,

  1. How do I load a partial snippet as a string, instead of a full HTML document?
  2. How do edit?
  3. How do I then return the text string of the edited object?
John
  • 3,332
  • 5
  • 33
  • 55

2 Answers2

30
  1. The same as a full HTML document. It doesn't matter.
  2. The are 2 options: you may edit InnerHtml property directly (or Text on text nodes) or modifying the dom tree by using e.g. AppendChild, PrependChild etc.
  3. You may use HtmlDocument.DocumentNode.OuterHtml property or use HtmlDocument.Save method (personally I prefer the second option).

As to parsing, I select the text nodes which contain the search term inside your div, and then just use string.Replace method to replace it:

var doc = new HtmlDocument();
doc.LoadHtml(html);
var textNodes = doc.DocumentNode.SelectNodes("/div/text()[contains(.,'specialSearchWord')]");
if (textNodes != null)
    foreach (HtmlTextNode node in textNodes)
        node.Text = node.Text.Replace("specialSearchWord", "<a class='special' href='http://mysite.com/search/specialSearchWord'>specialSearchWord</a>");

And saving the result to a string:

string result = null;
using (StringWriter writer = new StringWriter())
{
    doc.Save(writer);
    result = writer.ToString();
}
Oleks
  • 31,955
  • 11
  • 77
  • 132
  • 1
    Thanks. Multiple options. One thing that I did learn playing around with DOM manipulation is the usefulness of the following code: node.ParentNode.ReplaceChild(newNode, node) – John Mar 05 '12 at 16:40
  • HtmlDocument.DocumentNode.OuterHtml returns null and doc.Save() gives StackOverflowException How can i resolve it – Navin Gupta Jun 01 '17 at 07:32
  • @NavinGupta maybe, you have self-referencing nodes – Oleks Jun 01 '17 at 09:14
2

Answers:

  1. There may be a way to do this but I don't know how. I suggest loading the entire document.
  2. Use a combination of XPath and regular expressions
  3. See the code below for a contrived example. You may have other constraints not mentioned but this code sample should get you started.

Note that your Xpath expression may need to be more complex to find the div that you want.

HtmlDocument doc = new HtmlDocument();

doc.Load(yourHtmlFile);
HtmlNode divNode = doc.DocumentNode.SelectSingleNode("//div[2]");
string newDiv = Regex.Replace(divNode.InnerHtml, @"specialSearchWord", 
"<a class='special' href='http://etc'>specialSearchWord</a>");
divNode.InnerHtml = newDiv;
Console.WriteLine(doc.DocumentNode.OuterHtml);
Andrew Cowenhoven
  • 2,778
  • 22
  • 27