2011-06-10 16 views
1

我想這已經足夠普遍了,這是一個解決的問題,但作爲一個新手用絲瓜和Nokogiri我還沒找到解決方案。從包含< and >字符的文字中剝離含有絲瓜和Nokogiri字符的HTML

我正在使用一種包裝Nokogiri的HTML清除程序庫來清理一些HTML文本以供顯示。但是,該文本有時會發生在諸如電子郵件地址等<>之間的字符,例如<[email protected]>。絲瓜絡正在考慮將其作爲HTML或XML標籤,並將其從文本中剝離。

有沒有一種方法可以防止這種情況發生,同時還能很好地清除實際的標籤?

編輯:這是一個失敗的測試案例:

require 'test/unit' 
require 'test/unit/ui/console/testrunner' 
require 'nokogiri' 

MAGICAL_REGEXP = /<([^(?:\/|!\-\-)].*)>/ 

def filter_html(content) 
    # Current approach in a gist: We capture content enclosed in angle brackets. 
    # Then, we check if the excerpt right after the opening bracket is a valid HTML 
    # tag. If it's not, we substitute the matched content (which is the captured 
    # content enclosed in angle brackets) for the captured content enclosed in 
    # the HTML entities for the angle brackets. This does not work with nested 
    # HTML tags, since regular expressions are not meant for this. 

    content.to_s.gsub(MAGICAL_REGEXP) do |excerpt| 
    capture = $1 
    Nokogiri::HTML::ElementDescription[capture.split(/[<> ]/).first] ? excerpt : "&lt;#{capture}&gt;" 
    end 
end 

class HTMLTest < Test::Unit::TestCase 
    def setup 
    @raw_html = <<-EOS 
<html> 
<[email protected]> 
<p><[email protected]<b class="highlight">bar</b>.baz></p> 
<p> 
<[email protected]<b class="highlight">bar</b>.baz> 
</p> 
< don't erase this > 
</html> 
EOS 

    @filtered_html = <<-EOS 
<html> 
&lt;[email protected]&gt; 
<p>&lt;[email protected]<b class="highlight">bar</b>.baz&gt;</p> 
<p> 
&lt;[email protected]<b class="highlight">bar</b>.baz&gt; 
</p> 
&lt; don't erase this &gt; 
</html> 
EOS 
    end 

    def test_filter_html 
    assert_equal(@filtered_html, filter_html(@raw_html)) 
    end 
end 

# Can you make this test pass? 
Test::Unit::UI::Console::TestRunner.run(HTMLTest) 

目前,我們正在使用一些非常邪惡的正則表達式兩輪牛車,試圖做到這一點,但正如上面狀態的評論,它不工作標籤「嵌套「在非標籤內部。我們實際上也想保留<b class="highlight">元素。

下面的示例不使用絲瓜絡,但應用程序本身在其他地方,所以它不會很難在這裏添加它。我們只是不確定我們應該使用哪些配置選項,如果有的話。

+1

該文本實際上是否包含「<」字符或是否爲「<」實體? – 2011-06-10 15:39:14

+1

如果您提供了顯示問題的最小腳本(及其輸入和輸出),則回答起來會更容易。 – 2011-06-10 23:02:46

+0

@ mark-thomas:我編輯了這個問題來添加一個失敗的測試用例。我希望它能夠解決這個問題。 – Bira 2011-06-13 21:14:27

回答

2

由於主要問題是在HTML實體尖括號中包含的HTML標籤 - 這完全被Nokogiri弄壞 - 我們通過刪除上述HTML標籤,轉義非HTML標籤尖括號,然後放入HTML標籤回來。這聽起來有點駭人聽聞,但它的工作完美。我們的第一個目標是轉義尖括號中的電子郵件地址,但這種方法(據推測)適用於任何類型的文本。

# Does not run on ruby 1.9 

require 'test/unit' 
require 'test/unit/ui/console/testrunner' 
require 'nokogiri' 
require 'active_support/secure_random' 

def filter_html(content) 
    # Used to mark highlighted words. 
    random_hex = SecureRandom.hex(6) 

    # Remove highlighting. 
    highlighted_terms = [] 
    without_highlighting = content.to_s.gsub(/<b class="highlight">(.*?)<\/b>/) do |match| 
    highlighted_terms << $1 
    "highlight-#{random_hex}:#{$1}" 
    end 

    # Escape non-HTML angle brackets. 
    escaped_content = without_highlighting.to_s.gsub(/<(?:\s*\/)?([^!\-\-].*?)>/) do |excerpt| 
    capture = $1 
    tag = capture.split(/[^a-zA-Z1-6]/).reject(&:empty?).first 
    !!Nokogiri::HTML::ElementDescription[tag] ? excerpt : "&lt;#{capture}&gt;" 
    end 

    # Add highlighting back. 
    highlighted_terms.uniq.each do |term| 
    escaped_content.gsub!(/highlight-#{random_hex}:(#{term})/) do |match| 
     "<b class=\"highlight\">#{$1}</b>" 
    end 
    end 

    escaped_content 
end 

class HTMLTest < Test::Unit::TestCase 
    def setup 
    @raw_html = <<-EOS 
     <html> 
     <[email protected]> 
     <p><[email protected]<b class="highlight">bar</b>.baz></p> 
     <p> 
      <[email protected]<b class="highlight">bar</b>.baz> 
     </p> 
     < don't erase this > 
     </html> 
    EOS 

    @filtered_html = <<-EOS 
     <html> 
     &lt;[email protected]&gt; 
     <p>&lt;[email protected]<b class="highlight">bar</b>.baz&gt;</p> 
     <p> 
      &lt;[email protected]<b class="highlight">bar</b>.baz&gt; 
     </p> 
     &lt; don't erase this &gt; 
     </html> 
    EOS 
    end 

    def test_filter_html 
    assert_equal(@filtered_html, filter_html(@raw_html)) 
    end 
end 

# It passes! 
Test::Unit::UI::Console::TestRunner.run(HTMLTest) 
+1

這樣做並不是真正的黑客行爲。並不是所有的編程問題都能以直接或優雅的方式解決,特別是在處理HTML和XML時。有時我們必須變得非常骯髒,才能讓它工作,然後去某個地方從我們的口中獲得味道。這是任務的一部分。 – 2012-07-19 20:05:21

+0

澄清一些事情:「主要問題是HTML實體尖括號中包含的HTML標籤 - 這完全被Nokogiri弄壞了」。 Nokogiri沒有修改HTML,它試圖理解畸形的標記,關閉未正確關閉的標記,或者調整嵌入,以使HTML符合規範。您可以使用'errors'方法來查看解析的文檔的錯誤,以瞭解Nokogiri必須做的事情。有關如何使用Nokogiri清理格式錯誤的HTML的示例,請參閱http://stackoverflow.com/a/14515622/128421。 – 2013-01-25 06:23:42

相關問題