HTML Agility Pack Strip Tags Not in Whitelist

HTML Agility Pack strip tags NOT IN whitelist

heh, apparently I ALMOST found an answer in a blog post someone made....

using System.Collections.Generic;
using System.Linq;
using HtmlAgilityPack;

namespace Wayloop.Blog.Core.Markup
{
public static class HtmlSanitizer
{
private static readonly IDictionary<string, string[]> Whitelist;

static HtmlSanitizer()
{
Whitelist = new Dictionary<string, string[]> {
{ "a", new[] { "href" } },
{ "strong", null },
{ "em", null },
{ "blockquote", null },
};
}

public static string Sanitize(string input)
{
var htmlDocument = new HtmlDocument();

htmlDocument.LoadHtml(input);
SanitizeNode(htmlDocument.DocumentNode);

return htmlDocument.DocumentNode.WriteTo().Trim();
}

private static void SanitizeChildren(HtmlNode parentNode)
{
for (int i = parentNode.ChildNodes.Count - 1; i >= 0; i--) {
SanitizeNode(parentNode.ChildNodes[i]);
}
}

private static void SanitizeNode(HtmlNode node)
{
if (node.NodeType == HtmlNodeType.Element) {
if (!Whitelist.ContainsKey(node.Name)) {
node.ParentNode.RemoveChild(node);
return;
}

if (node.HasAttributes) {
for (int i = node.Attributes.Count - 1; i >= 0; i--) {
HtmlAttribute currentAttribute = node.Attributes[i];
string[] allowedAttributes = Whitelist[node.Name];
if (!allowedAttributes.Contains(currentAttribute.Name)) {
node.Attributes.Remove(currentAttribute);
}
}
}
}

if (node.HasChildNodes) {
SanitizeChildren(node);
}
}
}
}

I got HtmlSanitizer from here
Apparently it does not strip th tags, but removes the element altoghether.

OK, here is the solution for those who will need it later.

public static class HtmlSanitizer
{
private static readonly IDictionary<string, string[]> Whitelist;
private static List<string> DeletableNodesXpath = new List<string>();

static HtmlSanitizer()
{
Whitelist = new Dictionary<string, string[]> {
{ "a", new[] { "href" } },
{ "strong", null },
{ "em", null },
{ "blockquote", null },
{ "b", null},
{ "p", null},
{ "ul", null},
{ "ol", null},
{ "li", null},
{ "div", new[] { "align" } },
{ "strike", null},
{ "u", null},
{ "sub", null},
{ "sup", null},
{ "table", null },
{ "tr", null },
{ "td", null },
{ "th", null }
};
}

public static string Sanitize(string input)
{
if (input.Trim().Length < 1)
return string.Empty;
var htmlDocument = new HtmlDocument();

htmlDocument.LoadHtml(input);
SanitizeNode(htmlDocument.DocumentNode);
string xPath = HtmlSanitizer.CreateXPath();

return StripHtml(htmlDocument.DocumentNode.WriteTo().Trim(), xPath);
}

private static void SanitizeChildren(HtmlNode parentNode)
{
for (int i = parentNode.ChildNodes.Count - 1; i >= 0; i--)
{
SanitizeNode(parentNode.ChildNodes[i]);
}
}

private static void SanitizeNode(HtmlNode node)
{
if (node.NodeType == HtmlNodeType.Element)
{
if (!Whitelist.ContainsKey(node.Name))
{
if (!DeletableNodesXpath.Contains(node.Name))
{
//DeletableNodesXpath.Add(node.Name.Replace("?",""));
node.Name = "removeableNode";
DeletableNodesXpath.Add(node.Name);
}
if (node.HasChildNodes)
{
SanitizeChildren(node);
}

return;
}

if (node.HasAttributes)
{
for (int i = node.Attributes.Count - 1; i >= 0; i--)
{
HtmlAttribute currentAttribute = node.Attributes[i];
string[] allowedAttributes = Whitelist[node.Name];
if (allowedAttributes != null)
{
if (!allowedAttributes.Contains(currentAttribute.Name))
{
node.Attributes.Remove(currentAttribute);
}
}
else
{
node.Attributes.Remove(currentAttribute);
}
}
}
}

if (node.HasChildNodes)
{
SanitizeChildren(node);
}
}

private static string StripHtml(string html, string xPath)
{
HtmlDocument htmlDoc = new HtmlDocument();
htmlDoc.LoadHtml(html);
if (xPath.Length > 0)
{
HtmlNodeCollection invalidNodes = htmlDoc.DocumentNode.SelectNodes(@xPath);
foreach (HtmlNode node in invalidNodes)
{
node.ParentNode.RemoveChild(node, true);
}
}
return htmlDoc.DocumentNode.WriteContentTo(); ;
}

private static string CreateXPath()
{
string _xPath = string.Empty;
for (int i = 0; i < DeletableNodesXpath.Count; i++)
{
if (i != DeletableNodesXpath.Count - 1)
{
_xPath += string.Format("//{0}|", DeletableNodesXpath[i].ToString());
}
else _xPath += string.Format("//{0}", DeletableNodesXpath[i].ToString());
}
return _xPath;
}
}

I renamed the node because if I had to parse an XML namespace node it would crash on the xpath parsing.

HTML agility pack - removing unwanted tags without removing content?

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;
}

Stripping all html tags with Html Agility Pack

Why not just return htmldoc.DocumentNode.InnerText instead of removing all the non-text nodes? It should give you what you want.

Strip all HTML tags, except anchor tags

I suggest you use Html Agility Pack

also check this question/answers: HTML Agility Pack strip tags NOT IN whitelist

How to strip comments from HTML using Agility Pack without losing DOCTYPE

Check that comment does not start with DOCTYPE

  foreach (var comment in nodes)
{
if (!comment.InnerText.StartsWith("DOCTYPE"))
comment.ParentNode.RemoveChild(comment);
}

html agility pack remove children

bodyNode.RemoveChild(functionBarNode,false);

But functionBarNode is not a child of bodyNode.

How about functionBarNode.ParentNode.RemoveChild(functionBarNode, false)? (And forget the bit about finding bodyNode.)



Related Topics



Leave a reply



Submit