2009-09-30 30 views
9

有很多關於如何使用Ruby從文檔去除HTML標籤的例子,Hpricot和Nokogiri都有inner_text方法,可以方便快捷地爲您移除所有的HTML。使用Ruby去除HTML文檔中的文本

我想要做的是相反的,從HTML文檔中刪除所有文本,只留下標籤及其屬性。

我認爲循環遍歷文檔設置inner_html爲零,但然後真的,你必須做相反的第一個元素(根)有一個inner_html文檔的其餘部分,所以理想情況下,我會有從最內層的元素開始,並將inner_html設置爲零,同時通過祖先移動。

有沒有人知道這樣做有效的一個整潔的小技巧?我想也許正則表達式可能會這樣做,但可能不如HTML標記器/解析器可能有效。

+0

你將不得不面對糟糕的標記嗎? (未轉義的實體等) – Neall 2009-09-30 11:57:32

+0

這是可能的 - 我正在處理的標記來自最終用戶,因此無法依賴。 – davidsmalley 2009-09-30 13:09:28

回答

38

這工作太:

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

優秀!在結尾處扔一個'.to_s'來得到一個字符串,你很好走! – 2012-03-05 00:28:33

2

可以掃描字符串創建「標記」的數組,然後只選擇那些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>" 

== ==編輯

甚至更​​好,只需掃描HTML標記;)

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

搶不是在標籤的一切,你可以使用引入nokogiri這樣的:

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

當然,這會搶東西一樣的<script><style>標籤的內容,所以你也可以刪除黑名單標籤:

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

你也可以加入白名單,如果你首選,但是這可能會是更耗時:

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 

你也可以只建立一個龐大的XPath表達式,做一個搜索。我真的不知道哪種方式更快,或者甚至有可觀的區別。

0

我只是想出了這一點,但@安德烈-R的解決方案是好多了!

#!/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>