2010-06-29 19 views
16

que tienen una cadena HTML así:Excluyendo todas las etiquetas HTML con HTML agilidad Paquete

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

deseo de despojar todas las etiquetas HTML para que la cadena resultante se transforma en:

foo bar baz 

De otro post aquí en lo que he llegado con esta función (que utiliza el paquete de agilidad 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 

Desafortunadamente esto no hace r De acuerdo con lo que esperaba, en cambio da:

bazbarfoo 

Por favor, ¿dónde voy mal - y este es el mejor enfoque?

Saludos y feliz codificación!

ACTUALIZACIÓN: la respuesta a continuación me ocurrió con esta función, podría ser útil a los demás:

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

trabajando como un encanto - gracias de nuevo – Muleskinner

Respuesta

32

¿Por qué no volver htmldoc.DocumentNode.InnerText en lugar de eliminar todos los nodos que no son de texto? Debería darte lo que quieres.

-6

Usted puede utilizar el código siguiente.

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

gracias esto debería funcionar también – Muleskinner

+1

¿Qué pasa con otras cosas dentro de < > que no son etiquetas hTML? P.EJ. "John Smith <[email protected]>" este método lo despojaría. – JDwyer

+3

-1. El análisis de HTML con expresiones regulares rara vez es una buena idea. Consulte http://www.codinghorror.com/blog/2009/11/parsing-html-the-cthulhu-way.html – TrueWill

2

Elimina las etiquetas y las propiedades que no se encuentran en la lista blanca.

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

En su diccionario para todas las entradas excepto la primera, tiene 'Nothing' como valor. Es posible que pueda saltarse el uso de un mapa y usar una lista en su lugar. – Zasz

+0

Una "Lista" probablemente sea más lenta, aunque es poco probable que sea un cuello de botella. Dicho esto, en .Net 3.5+, recomendaría un 'HashSet' sobre una' Lista' para este propósito. – Brian

+0

Como Brian señala que la elección de la estructura de datos aquí es "poco probable que sea un cuello de botella". En comparación con las operaciones realizadas en cada nodo, ContainsKey es probablemente una parte insignificante, ¿no? –

1

Se parecen asumir que ParaCada atraviesa el documento de principio a fin .. si usted quiere asegurarse de que lo hace, utiliza un habitual de bucle. Ni siquiera se puede estar seguro de que los nodos están siendo recogidos en el orden que espera con el selector XPath, pero puede que tengas razón en esta ocasión ..

respecto, Brunis

0

editar a continuación algunas líneas, a continuación, se obtiene que desea ..

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 
Cuestiones relacionadas