HTML 敏捷包 - 删除不需要的标签而不删除内容?

Posted

技术标签:

【中文标题】HTML 敏捷包 - 删除不需要的标签而不删除内容?【英文标题】:HTML agility pack - removing unwanted tags without removing content? 【发布时间】:2012-09-29 00:59:58 【问题描述】:

我在这里看到了一些相关的问题,但它们并没有完全谈论我面临的同一个问题。

我想使用 html Agility Pack 从我的 HTML 中删除不需要的标签,而不会丢失标签中的内容。

例如,在我的场景中,我想保留标签“b”、“i”和“u”。

对于像这样的输入:

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

生成的 HTML 应该是:

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

我尝试使用HtmlNodeRemove 方法,但它也删除了我的内容。有什么建议吗?

【问题讨论】:

你试过HtmlNode.RemoveChild(HtmlNode oldChild, bool keepGrandChildren)的方法吗? 检查***.com/questions/18153998/… @bidou 如果必须强制执行安全性,我非常怀疑使用正则表达式是个好主意。 【参考方案1】:

我根据 Oded 的建议编写了一个算法。这里是。像魅力一样工作。

它会删除除strongemu 和原始文本节点之外的所有标签。

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;

【讨论】:

感谢您的解决方案!但请注意,它不会删除嵌套在可接受标签内的不可接受标签——例如,如果您允许“P”但不允许“SPAN”,则不会删除跨度。我通过递归运行此方法来解决此问题,从“var 节点...”拆分为一个单独的方法,该方法在可接受列表中的任何“节点”var 上调用自身并具有子节点。 伟大的@SeanMahan。随意使用您的解决方案编辑我的帖子 - 我相信它会更好:) @SeanMahan 请做!我想看看你的解决方案。 不适用于输入:'10 > 7 10 7 but 10' 但这也是非常无效的 HTML。【参考方案2】:

如何以递归方式从 html 字符串中删除给定的不需要的 html 标记列表

我接受了@mathias 的回答并改进了他的扩展方法,以便您可以提供要排除的标签列表作为List&lt;string&gt;(例如"a","p","hr")。我还修复了逻辑,使其递归地正常工作:

public static string RemoveUnwantedHtmlTags(this string html, List<string> unwantedTags)
    
        if (String.IsNullOrEmpty(html))
        
            return html;
        

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

        HtmlNodeCollection tryGetNodes = document.DocumentNode.SelectNodes("./*|./text()");

        if (tryGetNodes == null || !tryGetNodes.Any())
        
            return html;
        

        var nodes = new Queue<HtmlNode>(tryGetNodes);

        while (nodes.Count > 0)
        
            var node = nodes.Dequeue();
            var parentNode = node.ParentNode;

            var childNodes = node.SelectNodes("./*|./text()");

            if (childNodes != null)
            
                foreach (var child in childNodes)
                
                    nodes.Enqueue(child);                       
                
            

            if (unwantedTags.Any(tag => tag == node.Name))
                           
                if (childNodes != null)
                
                    foreach (var child in childNodes)
                    
                        parentNode.InsertBefore(child, node);
                    
                

                parentNode.RemoveChild(node);

            
        

        return document.DocumentNode.InnerHtml;
    

【讨论】:

注意:如果我没看错,这个函数会删除不需要的标签列表,@mathias 发布的函数会保留可接受的标签。这是完全不同的。 @StarQuake 这是对原始问题的回答,即删除不需要的标签。我刚刚修改了 Mathias 的代码,使其更加灵活。 原始问题询问如何通过提供 allowedTags 来删除不需要的标签。原始问题的标题具有误导性。给出的示例还说明了一个保留 allowedTags 的函数,而不是删除不允许的标签。 @StarQuake 这个问题没有提到任何关于需要“allowedTags”列表的实现,它只是给出了一个要在一个实例中保留的标签的例子。 Mathias 的回答通过硬编码的白名单方法给出了解决方案。我的回答通过可变黑名单方法提供了一个解决方案,以增加灵活性。既没有对错,也没有对错,只是原始问题的替代解决方案。【参考方案3】:

如果您不想使用 Html 敏捷包,但仍想删除不需要的 Html 标签,则可以执行以下操作。

public static string RemoveHtmlTags(string strHtml)
    
        string strText = Regex.Replace(strHtml, "<(.|\n)*?>", String.Empty);
        strText = HttpUtility.HtmlDecode(strText);
        strText = Regex.Replace(strText, @"\s+", " ");
        return strText;
    

【讨论】:

请勿使用正则表达式解析或分析 HTML。【参考方案4】:

尝试以下方法,您可能会发现它比其他建议的解决方案更简洁:

public static int RemoveNodesButKeepChildren(this HtmlNode rootNode, string xPath)

    HtmlNodeCollection nodes = rootNode.SelectNodes(xPath);
    if (nodes == null)
        return 0;
    foreach (HtmlNode node in nodes)
        node.RemoveButKeepChildren();
    return nodes.Count;


public static void RemoveButKeepChildren(this HtmlNode node)

    foreach (HtmlNode child in node.ChildNodes)
        node.ParentNode.InsertBefore(child, node);
    node.Remove();


public static bool TestYourSpecificExample()

    string html = "<p>my paragraph <div>and my <b>div</b></div> are <i>italic</i> and <b>bold</b></p>";
    HtmlDocument document = new HtmlDocument();
    document.LoadHtml(html);
    document.DocumentNode.RemoveNodesButKeepChildren("//div");
    document.DocumentNode.RemoveNodesButKeepChildren("//p");
    return document.DocumentNode.InnerHtml == "my paragraph and my <b>div</b> are <i>italic</i> and <b>bold</b>";

【讨论】:

【参考方案5】:

在删除节点之前,获取其父节点及其InnerText,然后删除节点并将InnerText 重新分配给父节点。

var parent = node.ParentNode;
var innerText = parent.InnerText;
node.Remove();
parent.AppendChild(doc.CreateTextNode(innerText));

【讨论】:

InnerText 破坏了层次结构。想象更多深度,例如:&lt;p&gt;my &lt;b&gt;paragraph &lt;div&gt;and my &lt;b&gt;&lt;span&gt;&lt;i&gt;div&lt;/i&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt; are &lt;i&gt;italic&lt;/i&gt; and &lt;b&gt;bold&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;。 InnerText 搞砸了 HTML 并将其转换为文本,但这并不是我在所有情况下都想要的。我仍然想要允许标签的 HTML。 @MathiasLykkegaardLorenzen - 我的意思是您只使用 unwanted 元素。 是的。但是,如果您在这里查看这些数据会怎样。 lalala &lt;span&gt;omg &lt;b&gt;this&lt;/b&gt; is bold&lt;/span&gt;。首先,您会发现 span 元素。这是不允许的,所以你用它的InnerText 值交换它。但是,这会破坏我仍然需要的内部 b 标签。我希望这能更好地解释它。 @MathiasLykkegaardLorenzen - 当然,您可以简单地执行 same 但使用 nodeInnerHtml 而不是父节点(也就是说,采取节点的InnerHtml 并在删除节点后替换父InnerHtml)。您也可以使用节点的InnerHtml 递归地执行此操作。 谢谢 - 我会尝试并回复你。

以上是关于HTML 敏捷包 - 删除不需要的标签而不删除内容?的主要内容,如果未能解决你的问题,请参考以下文章

如何从呈现的文本中删除 HTML 标签

删除捆绑包中的 MSI 包而不包括源

从字符串中删除 html 图像标签和介于两者之间的所有内容

Jquery追加而不删除

如何使用 java 代码重命名和移动文件而不删除内容

总结php删除html标签和标签内的内容的方法