【问题标题】:Stripping HTML from text containing < and > characters with Loofah and Nokogiri使用 Loofah 和 Nokogiri 从包含 < 和 > 字符的文本中剥离 HTML
【发布时间】:2012-07-20 04:03:23
【问题描述】:

我想这很常见,以至于它是一个已解决的问题,但作为丝瓜和 Nokogiri 的新手,我还没有找到解决方案。

我正在使用 Loofah,一个包装 Nokogiri 的 HTML 清理器库,用于清理一些 HTML 文本以供显示。但是,该文本有时会出现在电子邮件地址等&lt;&gt; 字符之间,例如&lt; foo@domain.com &gt;。 Loofah 将其视为 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>
<foo@bar.baz>
<p><foo@<b class="highlight">bar</b>.baz></p>
<p>
<foo@<b class="highlight">bar</b>.baz>
</p>
< don't erase this >
</html>
EOS

    @filtered_html = <<-EOS
<html>
&lt;foo@bar.baz&gt;
<p>&lt;foo@<b class="highlight">bar</b>.baz&gt;</p>
<p>
&lt;foo@<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)

我们目前正在使用一些非常邪恶的正则表达式黑客来尝试实现这一点,但正如上面的评论所述,它不适用于“嵌套”在非标签中的标签。我们实际上也想保留&lt;b class="highlight"&gt; 元素。

下面的示例没有使用丝瓜络,但应用程序本身在其他地方使用丝瓜络,所以在这里添加它并不难。我们只是不确定应该使用哪些配置选项(如果有的话)。

【问题讨论】:

  • 文本是否实际包含“
  • 如果您提供一个显示问题的最小脚本(连同它的输入和输出),这将更容易回答。
  • @mark-thomas :我已编辑问题以添加失败的测试用例。我希望它可以解决这个问题。
  • @andy-waite :正如上面的测试所示,文本实际上包含一个

标签: html ruby nokogiri


【解决方案1】:

由于主要问题是 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>
        <foo@bar.baz>
        <p><foo@<b class="highlight">bar</b>.baz></p>
        <p>
          <foo@<b class="highlight">bar</b>.baz>
        </p>
        <    don't erase this   >
      </html>
    EOS

    @filtered_html = <<-EOS
      <html>
        &lt;foo@bar.baz&gt;
        <p>&lt;foo@<b class="highlight">bar</b>.baz&gt;</p>
        <p>
          &lt;foo@<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)

【讨论】:

  • 这样做并不是一个真正的黑客行为。并非所有的编程问题都能以直接或优雅的方式得到解决,尤其是在处理 HTML 和 XML 时。有时我们必须弄得非常脏,让它发挥作用,然后去某个地方把味道从嘴里吐出来。这是任务的一部分。
  • 澄清一下:“主要问题是 HTML 实体尖括号中的 HTML 标签——这完全被 Nokogiri 破坏了”。 Nokogiri 并没有破坏 HTML,它试图理解格式错误的标记,关闭未正确关闭的标签,或调整嵌入以使 HTML 符合规范。您可以使用errors 方法查看已解析文档的错误,以了解 Nokogiri 必须执行的操作。请参阅stackoverflow.com/a/14515622/128421,了解我如何使用 Nokogiri 清理格式错误的 HTML。
猜你喜欢
  • 2012-09-30
  • 2022-12-27
  • 1970-01-01
  • 2011-06-18
  • 2011-05-02
  • 1970-01-01
  • 2011-06-04
  • 1970-01-01
  • 2011-11-16
相关资源
最近更新 更多