public static void Main()
string html = @"<h1> Title 1 </h1>
<p>Lorem ipsum dolor...</p>
<h2> Title 2 Different </h2>";
string resultHtml = ReplaceHeaderHtml(html);
Console.Write(resultHtml);
private static string ReplaceHeaderHtml(string html)
var doc = new HtmlDocument();
var xpath = "//*[self::h1 or self::h2 or self::h3 or self::h4]";
HtmlNodeCollection headers = doc.DocumentNode.SelectNodes(xpath);
if (headers == null || headers.Count == 0)
.Where(node => !"a".Equals(node.PreviousSibling?.OriginalName, StringComparison.InvariantCultureIgnoreCase))
for(int i = 0; i < headerList.Count; i++)
var header = headerList[i];
var parentNode = header.ParentNode;
int headerIndex = parentNode.ChildNodes.IndexOf(header);
HtmlNode div = doc.CreateElement("div");
HtmlNode anchor = doc.CreateElement("a");
switch(header.OriginalName)
case "h1": href = "#my_slugged__link_by_title"; break;
case "h2": href = "#my_slugged__link_by_title_2"; break;
case "h3": href = "#my_slugged__link_by_title_3"; break;
default: href = "#my_slugged__link_by_title"; break;
anchor.Attributes.Add("class", "header_link");
anchor.Attributes.Add("href", href);
div.ChildNodes.Add(anchor);
div.ChildNodes.Add(header);
parentNode.ChildNodes.Remove(header);
parentNode.ChildNodes.Insert(headerIndex, div);
return doc.DocumentNode.OuterHtml;