Las tags HTML Agility Pack NO están en la lista blanca

Intento crear una función que elimine las tags html y los atributos que no están en una lista blanca. Tengo el siguiente HTML:

first text  second text here some text here some text here  some twxt here 

Estoy usando HTML Agility Pack y el código que tengo hasta ahora es:

 static List WhiteNodeList = new List { "b" }; static List WhiteAttrList = new List { }; static HtmlNode htmlNode; public static void RemoveNotInWhiteList(out string _output, HtmlNode pNode, List pWhiteList, List attrWhiteList) { // remove all attributes not on white list foreach (var item in pNode.ChildNodes) { item.Attributes.Where(u => attrWhiteList.Contains(u.Name) == false).ToList().ForEach(u => RemoveAttribute(u)); } // remove all html and their innerText and attributes if not on whitelist. //pNode.ChildNodes.Where(u => pWhiteList.Contains(u.Name) == false).ToList().ForEach(u => u.Remove()); //pNode.ChildNodes.Where(u => pWhiteList.Contains(u.Name) == false).ToList().ForEach(u => u.ParentNode.ReplaceChild(ConvertHtmlToNode(u.InnerHtml),u)); //pNode.ChildNodes.Where(u => pWhiteList.Contains(u.Name) == false).ToList().ForEach(u => u.Remove()); for (int i = 0; i < pNode.ChildNodes.Count; i++) { if (!pWhiteList.Contains(pNode.ChildNodes[i].Name)) { HtmlNode _newNode = ConvertHtmlToNode(pNode.ChildNodes[i].InnerHtml); pNode.ChildNodes[i].ParentNode.ReplaceChild(_newNode, pNode.ChildNodes[i]); if (pNode.ChildNodes[i].HasChildNodes && !string.IsNullOrEmpty(pNode.ChildNodes[i].InnerText.Trim().Replace("\r\n", ""))) { HtmlNode outputNode1 = pNode.ChildNodes[i]; for (int j = 0; j < pNode.ChildNodes[i].ChildNodes.Count; j++) { string _childNodeOutput; RemoveNotInWhiteList(out _childNodeOutput, pNode.ChildNodes[i], WhiteNodeList, WhiteAttrList); pNode.ChildNodes[i].ReplaceChild(ConvertHtmlToNode(_childNodeOutput), pNode.ChildNodes[i].ChildNodes[j]); i++; } } } } // Console.WriteLine(pNode.OuterHtml); _output = pNode.OuterHtml; } private static void RemoveAttribute(HtmlAttribute u) { u.Value = u.Value.ToLower().Replace("javascript", ""); u.Remove(); } public static HtmlNode ConvertHtmlToNode(string html) { HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument(); doc.LoadHtml(html); if (doc.DocumentNode.ChildNodes.Count == 1) return doc.DocumentNode.ChildNodes[0]; else return doc.DocumentNode; } 

La salida que bash lograr es

 first text  second text here some text here some text here  some twxt here 

Eso significa que solo quiero mantener las tags .
La razón por la que estoy haciendo esto es porque algunos de los usuarios copian y pegan desde MS WORD en el editor de wywsywyg html.

Gracias.!

heh, aparentemente CASI encontré una respuesta en una publicación de blog que alguien hizo …

 using System.Collections.Generic; using System.Linq; using HtmlAgilityPack; namespace Wayloop.Blog.Core.Markup { public static class HtmlSanitizer { private static readonly IDictionary Whitelist; static HtmlSanitizer() { Whitelist = new Dictionary { { "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); } } } } 

Obtuve HtmlSanitizer desde aquí Aparentemente no quita las tags, pero elimina el elemento por completo.

OK, aquí está la solución para aquellos que la necesitarán más tarde.

 public static class HtmlSanitizer { private static readonly IDictionary Whitelist; private static List DeletableNodesXpath = new List(); static HtmlSanitizer() { Whitelist = new Dictionary { { "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; } } 

Cambié el nombre del nodo porque si tuviera que analizar un nodo de espacio de nombres XML se bloquearía en el análisis xpath.

Gracias por el código, ¡¡¡gran cosa !!

Hice pocas optimizaciones …

 class TagSanitizer { List _deleteNodes = new List(); public static void Sanitize(HtmlNode node) { new TagSanitizer().Clean(node); } void Clean(HtmlNode node) { CleanRecursive(node); for (int i = _deleteNodes.Count - 1; i >= 0; i--) { HtmlNode nodeToDelete = _deleteNodes[i]; nodeToDelete.ParentNode.RemoveChild(nodeToDelete, true); } } void CleanRecursive(HtmlNode node) { if (node.NodeType == HtmlNodeType.Element) { if (Config.TagsWhiteList.ContainsKey(node.Name) == false) { _deleteNodes.Add(node); } else if (node.HasAttributes) { for (int i = node.Attributes.Count - 1; i >= 0; i--) { HtmlAttribute currentAttribute = node.Attributes[i]; string[] allowedAttributes = Config.TagsWhiteList[node.Name]; if (allowedAttributes != null) { if (allowedAttributes.Contains(currentAttribute.Name) == false) { node.Attributes.Remove(currentAttribute); } } else { node.Attributes.Remove(currentAttribute); } } } } if (node.HasChildNodes) { node.ChildNodes.ToList().ForEach(v => CleanRecursive(v)); } } }