2009-09-30 26 views
9

Hay muchos ejemplos de cómo quitar etiquetas HTML de un documento utilizando Ruby, Hpricot y Nokogiri con métodos de texto interno que eliminan todo el HTML para usted de manera fácil y rápida.Eliminar texto del documento HTML con Ruby

Lo que intento hacer es lo contrario, eliminar todo el texto de un documento HTML, dejando solo las etiquetas y sus atributos.

Consideré el bucle a través de la configuración del documento inner_html a nil, pero en realidad tendrías que hacer esto a la inversa ya que el primer elemento (root) tiene un inner_html del resto del documento, así que idealmente tendría para comenzar en el elemento más interno y establecer inner_html en nil mientras se mueve hacia arriba a través de los antepasados.

¿Alguien sabe un pequeño truco para hacer esto de manera eficiente? Estaba pensando que tal vez Regex podría hacerlo, pero probablemente no tan eficientemente como lo haría un tokenizer/analizador de HTML.

+0

¿Va a tener que lidiar con un marcado incorrecto? (entidades no guardadas, etc.) – Neall

+0

Es posible: el marcado que estoy procesando proviene de usuarios finales, por lo que no se puede confiar en ellos. – davidsmalley

Respuesta

38

Esto funciona también:

doc = Nokogiri::HTML(your_html) 
doc.xpath("//text()").remove 
+1

¡Excelente! Mezcle un '.to_s' al final para obtener un hilo y ¡listo! –

2

Puede escanear la cadena para crear una serie de "fichas", y sólo seleccionar aquellos que son etiquetas HTML:

>> some_html 
=> "<div>foo bar</div><p>I like <em>this</em> stuff <a href='http://foo.bar'> long time</a></p>" 
>> some_html.scan(/<\/?[^>]+>|[\w\|`[email protected]#\$%^&*\(\)\-_\+=\[\]{}:;'",\.\/?]+|\s+/).select { |t| t =~ /<\/?[^>]+>/ }.join("") 
=> "<div></div><p><em></em><a href='http://foo.bar'></a></p>" 

Editar == ==

O incluso mejor, sólo escaneo para etiquetas html;)

>> some_html.scan(/<\/?[^>]+>/).join("") 
=> "<div></div><p><em></em><a href='http://foo.bar'></a></p>" 
3

para agarrar todo lo que no esté en una etiqueta, puede utilizar nokogiri así:

doc.search('//text()').text 

Por supuesto, que atraerá cosas como el contenido de <script> o <style> etiquetas, por lo que también podría quitar las etiquetas de la lista negra:

blacklist = ['title', 'script', 'style'] 
nodelist = doc.search('//text()') 
blacklist.each do |tag| 
    nodelist -= doc.search('//' + tag + '/text()') 
end 
nodelist.text 

También podría lista blanca si preferido, pero que probablemente va a ser más requiere mucho tiempo:

whitelist = ['p', 'span', 'strong', 'i', 'b'] #The list goes on and on... 
nodelist = Nokogiri::XML::NodeSet.new(doc) 
whitelist.each do |tag| 
    nodelist += doc.search('//' + tag + '/text()') 
end 
nodelist.text 

También puede crear una enorme expresión XPath y hacer una búsqueda. Honestamente, no sé qué camino es más rápido, o si incluso hay una diferencia apreciable.

0

Me acaba de llegar con esto, pero la solución de @ Andre-r es taaan mucho mejor!

#!/usr/bin/env ruby 

require 'nokogiri' 

def strip_text doc 
    Nokogiri(doc).tap { |doc| 
    doc.traverse do |node| 
     node.content = nil if node.text? 
    end 
    }.to_s 
end 

require 'test/unit' 
require 'yaml' 
class TestHTMLStripping < Test::Unit::TestCase 
    def test_that_all_text_gets_strippped_from_the_document 
    dirty, clean = YAML.load DATA 
    assert_equal clean, strip_text(dirty) 
    end 
end 
__END__ 
--- 
- | 
    <!DOCTYPE html> 
    <html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'> 
    <head> 
     <meta http-equiv='Content-type'  content='text/html; charset=UTF-8' /> 
     <title>Test HTML Document</title> 
     <meta http-equiv='content-language' content='en' /> 
    </head> 
    <body> 
     <h1>Test <abbr title='Hypertext Markup Language'>HTML</abbr> Document</h1> 
     <div class='main'> 
      <p> 
       <strong>Test</strong> <abbr title='Hypertext Markup Language'>HTML</abbr> <em>Document</em> 
      </p> 
     </div> 
    </body> 
    </html> 
- | 
    <!DOCTYPE html> 
    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> 
    <head> 
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 
    <title></title> 
    <meta http-equiv="content-language" content="en"> 
    </head> 
    <body><h1><abbr title="Hypertext Markup Language"></abbr></h1><div class="main"><p><strong></strong><abbr title="Hypertext Markup Language"></abbr><em></em></p></div></body> 
    </html> 
Cuestiones relacionadas