HTML agility pack - removing unwanted tags without removing content?

Mathias Lykkegaard Lorenzen picture Mathias Lykkegaard Lorenzen · Oct 8, 2012 · Viewed 45.7k times · Source

I've seen a few related questions out here, but they don’t exactly talk about the same problem I am facing.

I want to use the HTML Agility Pack to remove unwanted tags from my HTML without losing the content within the tags.

So for instance, in my scenario, I would like to preserve the tags "b", "i" and "u".

And for an input like:

<p>my paragraph <div>and my <b>div</b></div> are <i>italic</i> and <b>bold</b></p>

The resulting HTML should be:

my paragraph and my <b>div</b> are <i>italic</i> and <b>bold</b>

I tried using HtmlNode's Remove method, but it removes my content too. Any suggestions?

Answer

Mathias Lykkegaard Lorenzen picture Mathias Lykkegaard Lorenzen · Oct 11, 2012

I wrote an algorithm based on Oded's suggestions. Here it is. Works like a charm.

It removes all tags except strong, em, u and raw text nodes.

internal static string RemoveUnwantedTags(string data)
{
    if(string.IsNullOrEmpty(data)) return string.Empty;

    var document = new HtmlDocument();
    document.LoadHtml(data);

    var acceptableTags = new String[] { "strong", "em", "u"};

    var nodes = new Queue<HtmlNode>(document.DocumentNode.SelectNodes("./*|./text()"));
    while(nodes.Count > 0)
    {
        var node = nodes.Dequeue();
        var parentNode = node.ParentNode;

        if(!acceptableTags.Contains(node.Name) && node.Name != "#text")
        {
            var childNodes = node.SelectNodes("./*|./text()");

            if (childNodes != null)
            {
                foreach (var child in childNodes)
                {
                    nodes.Enqueue(child);
                    parentNode.InsertBefore(child, node);
                }
            }

            parentNode.RemoveChild(node);

        }
    }

    return document.DocumentNode.InnerHtml;
}