【问题标题】:Stripping all html tags with Html Agility Pack使用 Html Agility Pack 剥离所有 html 标签
【发布时间】:2010-06-29 13:11:47
【问题描述】:

我有一个这样的 html 字符串:

<html><body><p>foo <a href='http://www.example.com'>bar</a> baz</p></body></html>

我希望去掉所有的 html 标签,这样生成的字符串就变成了:

foo bar baz

从 SO 的另一篇文章中,我提出了这个功能(它使用 Html 敏捷包):

  Public Shared Function stripTags(ByVal html As String) As String
    Dim plain As String = String.Empty
    Dim htmldoc As New HtmlAgilityPack.HtmlDocument

    htmldoc.LoadHtml(html)
    Dim invalidNodes As HtmlAgilityPack.HtmlNodeCollection = htmldoc.DocumentNode.SelectNodes("//html|//body|//p|//a")

    If Not htmldoc Is Nothing Then
      For Each node In invalidNodes
        node.ParentNode.RemoveChild(node, True)
      Next
    End If

    Return htmldoc.DocumentNode.WriteContentTo
  End Function

不幸的是,这并没有返回我所期望的,而是给出了:

bazbarfoo

请问,我哪里出错了 - 这是最好的方法吗?

祝您编码愉快!

更新:通过下面的答案我想出了这个功能,可能对其他人有用:

  Public Shared Function stripTags(ByVal html As String) As String
    Dim htmldoc As New HtmlAgilityPack.HtmlDocument
    htmldoc.LoadHtml(html.Replace("</p>", "</p>" & New String(Environment.NewLine, 2)).Replace("<br/>", Environment.NewLine))
    Return htmldoc.DocumentNode.InnerText
  End Function

【问题讨论】:

  • 工作就像一个魅力 - 再次感谢

标签: html vb.net html-agility-pack strip


【解决方案1】:

为什么不直接返回htmldoc.DocumentNode.InnerText 而不是删除所有非文本节点?它应该给你你想要的。

【讨论】:

    【解决方案2】:

    它会删除白名单中没有的标签和属性。

    Public NotInheritable Class HtmlSanitizer
        Private Sub New()
        End Sub
        Private Shared ReadOnly Whitelist As IDictionary(Of String, String())
        Private Shared DeletableNodesXpath As New List(Of String)()
    
        Shared Sub New()
            Whitelist = New Dictionary(Of String, String())() From { _
                {"a", New () {"href"}}, _
                {"strong", Nothing}, _
                {"em", Nothing}, _
                {"blockquote", Nothing}, _
                {"b", Nothing}, _
                {"p", Nothing}, _
                {"ul", Nothing}, _
                {"ol", Nothing}, _
                {"li", Nothing}, _
                {"div", New () {"align"}}, _
                {"strike", Nothing}, _
                {"u", Nothing}, _
                {"sub", Nothing}, _
                {"sup", Nothing}, _
                {"table", Nothing}, _
                {"tr", Nothing}, _
                {"td", Nothing}, _
                {"th", Nothing} _
            }
        End Sub
    
        Public Shared Function Sanitize(input As String) As String
            If input.Trim().Length < 1 Then
                Return String.Empty
            End If
            Dim htmlDocument = New HtmlDocument()
    
            htmlDocument.LoadHtml(input)
            SanitizeNode(htmlDocument.DocumentNode)
            Dim xPath As String = HtmlSanitizer.CreateXPath()
    
            Return StripHtml(htmlDocument.DocumentNode.WriteTo().Trim(), xPath)
        End Function
    
        Private Shared Sub SanitizeChildren(parentNode As HtmlNode)
            For i As Integer = parentNode.ChildNodes.Count - 1 To 0 Step -1
                SanitizeNode(parentNode.ChildNodes(i))
            Next
        End Sub
    
        Private Shared Sub SanitizeNode(node As HtmlNode)
            If node.NodeType = HtmlNodeType.Element Then
                If Not Whitelist.ContainsKey(node.Name) Then
                    If Not DeletableNodesXpath.Contains(node.Name) Then
                        'DeletableNodesXpath.Add(node.Name.Replace("?",""));
                        node.Name = "removeableNode"
                        DeletableNodesXpath.Add(node.Name)
                    End If
                    If node.HasChildNodes Then
                        SanitizeChildren(node)
                    End If
    
                    Return
                End If
    
                If node.HasAttributes Then
                    For i As Integer = node.Attributes.Count - 1 To 0 Step -1
                        Dim currentAttribute As HtmlAttribute = node.Attributes(i)
                        Dim allowedAttributes As String() = Whitelist(node.Name)
                        If allowedAttributes IsNot Nothing Then
                            If Not allowedAttributes.Contains(currentAttribute.Name) Then
                                node.Attributes.Remove(currentAttribute)
                            End If
                        Else
                            node.Attributes.Remove(currentAttribute)
                        End If
                    Next
                End If
            End If
    
            If node.HasChildNodes Then
                SanitizeChildren(node)
            End If
        End Sub
    
        Private Shared Function StripHtml(html As String, xPath As String) As String
            Dim htmlDoc As New HtmlDocument()
            htmlDoc.LoadHtml(html)
            If xPath.Length > 0 Then
                Dim invalidNodes As HtmlNodeCollection = htmlDoc.DocumentNode.SelectNodes(xPath)
                For Each node As HtmlNode In invalidNodes
                    node.ParentNode.RemoveChild(node, True)
                Next
            End If
            Return htmlDoc.DocumentNode.WriteContentTo()
    
    
        End Function
    
        Private Shared Function CreateXPath() As String
            Dim _xPath As String = String.Empty
            For i As Integer = 0 To DeletableNodesXpath.Count - 1
                If i IsNot DeletableNodesXpath.Count - 1 Then
                    _xPath += String.Format("//{0}|", DeletableNodesXpath(i).ToString())
                Else
                    _xPath += String.Format("//{0}", DeletableNodesXpath(i).ToString())
                End If
            Next
            Return _xPath
        End Function
    End Class
    

    【讨论】:

    • 在您的字典中,除了第一个条目之外的所有条目,您的值都是“Nothing”。您可能可以跳过使用地图并改用列表。
    • A List 可能会更慢,尽管它不太可能成为瓶颈。话虽如此,在 .Net 3.5+ 上,我会为此推荐 HashSet 而不是 List。
    • 正如 Brian 指出的那样,这里的数据结构选择“不太可能成为瓶颈”。与在每个节点上执行的操作相比, ContainsKey 可能是可以忽略不计的部分,不是吗?
    【解决方案3】:

    您似乎假设 ForEach 从头到尾遍历文档。如果您想确保这样做,请使用常规 for 循环。您甚至无法确定使用 xpath 选择器是否按照您期望的顺序拾取节点,但在这种情况下您可能是对的..

    问候, 布鲁尼斯

    【讨论】:

      【解决方案4】:

      编辑下面几行,然后你得到你想要的..

      Private Shared Function StripHtml(html As String, xPath As String) As String
          Dim htmlDoc As New HtmlAgilityPack.HtmlDocument()
          htmlDoc.LoadHtml(html)
          If xPath.Length > 0 Then
              Dim invalidNodes As HtmlNodeCollection = htmlDoc.DocumentNode.SelectNodes(xPath)
      
              '------- edit this line -------------------
              'For Each node As HtmlNode In invalidNodes
              'node.ParentNode.RemoveChild(node, True)
              'Next
              '
              ' result-> bazbarfoo
              '
      
              '------- modify line ----------------------
              For i = invalidNodes.Count - 1 To 0 Step -1
                  Dim Node As HtmlNode = invalidNodes.Item(i)
                  Node.ParentNode.RemoveChild(Node, True)
              Next
              '
              ' result-> foo bar baz
              '
          End If
          Return htmlDoc.DocumentNode.WriteContentTo()
      
      
      End Function
      

      【讨论】:

        【解决方案5】:

        您可以使用以下代码。

        public string RemoveHTMLTags(string source)
        {
             string expn = "<.*?>";
             return Regex.Replace(source, expn, string.Empty);
        }
        

        【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-02-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-28
        • 2017-04-13
        相关资源
        最近更新 更多