2010-06-29 43 views
16

Tôi có một chuỗi html như thế này:Tước tất cả các thẻ html với Html Agility Pack

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

Tôi muốn tước tất cả các thẻ html để các chuỗi kết quả trở thành:

foo bar baz 

Từ bài khác ở đây tại SO Tôi đã đưa ra chức năng này (sử dụng Gói Agility 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 

Thật không may điều này không r và những gì tôi mong đợi, thay vào đó nó cho:

bazbarfoo 

Làm ơn đi đâu - và đây có phải là cách tiếp cận tốt nhất không?

Kính trọng và mã hóa vui vẻ!

UPDATE: bởi câu trả lời dưới đây tôi đã đưa ra chức năng này, có thể có ích cho người khác:

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 
+0

làm việc như một nét duyên dáng - nhờ một lần nữa cám ơn – Muleskinner

Trả lời

32

Tại sao không trả lại htmldoc.DocumentNode.InnerText thay vì xóa tất cả các nút không phải là văn bản? Nó sẽ cung cấp cho bạn những gì bạn muốn.

-6

Bạn có thể sử dụng đoạn mã sau.

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

này nên làm việc quá – Muleskinner

+1

gì về những thứ khác bên trong < > mà không phải là thẻ html? VÍ DỤ. "John Smith <[email protected]>" phương pháp này sẽ loại bỏ điều đó. – JDwyer

+3

-1. Phân tích cú pháp HTML với các biểu thức chính quy hiếm khi là một ý tưởng hay. Xem http://www.codinghorror.com/blog/2009/11/parsing-html-the-cthulhu-way.html – TrueWill

2

Loại bỏ các thẻ và thuộc tính không được tìm thấy trong danh sách trắng.

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 
+0

Trong từ điển của bạn cho tất cả các mục ngoại trừ mục nhập đầu tiên, bạn có 'Không có gì' làm giá trị. Bạn có thể có khả năng bỏ qua bằng cách sử dụng bản đồ và sử dụng danh sách thay thế. – Zasz

+0

Một 'Danh sách' có thể sẽ chậm hơn, mặc dù đó không phải là nút cổ chai. Điều đó đang được nói, trên. Net 3.5+, tôi muốn giới thiệu một 'HashSet' trên một' Danh sách' cho mục đích này. – Brian

+0

Như Brian chỉ ra sự lựa chọn cấu trúc dữ liệu ở đây là "không thể là một nút cổ chai". So với các hoạt động được thực hiện trên mỗi nút, ContainsKey có lẽ là một phần không đáng kể, phải không? –

1

01 Bạn dường như giả định rằng ForEach duyệt tài liệu từ đầu đến cuối .. nếu bạn muốn đảm bảo bạn làm điều đó, hãy sử dụng vòng lặp thông thường. Bạn thậm chí không thể chắc chắn các nút đang được nhặt theo thứ tự bạn mong đợi với bộ chọn xpath, nhưng bạn có thể phải vào dịp này ..

regards, Brunis

0

chỉnh sửa bên dưới vài dòng, sau đó bạn nhận được rằng bạn muốn ..

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 
Các vấn đề liên quan