【问题标题】:Sanitizing HTML using Nokogiri使用 Nokogiri 清理 HTML
【发布时间】:2014-09-16 16:08:58
【问题描述】:

我正在尝试清理一些 CMS 输入的 HTML,这些 HTML 到处都有无关的段落标签和 br 标签。事实证明,Sanitize gem 非常有用,但我遇到了一个特定问题。

问题是当段落标记之后/之前直接有一个 br 标记时,例如

<p>
  <br />
  Some text here
  <br />
  Some more text
  <br />
</p>

我想去掉多余的第一个和最后一个 br 标签,但不是中间的。

我非常希望我可以使用清理转换器来做到这一点,但似乎找不到合适的匹配器来实现这一点。

任何帮助将不胜感激。

【问题讨论】:

  • 我对 sanitize 不熟悉,但 /&lt;br \/&gt;(.*)&lt;br \/&gt;/ 会匹配中间部分,没有前导 &lt;br /&gt; 标签。
  • 不要使用正则表达式来操作 HTML。解决方案太脆弱了。
  • 而且,您确实需要向我们展示您的尝试。这让我们知道您想知道如何钓鱼,而不仅仅是要求钓鱼。

标签: html ruby-on-rails ruby nokogiri sanitize


【解决方案1】:

以下是定位 &lt;p&gt; 包含的特定 &lt;br&gt; 节点的方法:

require 'nokogiri'

doc = Nokogiri::HTML::DocumentFragment.parse(<<EOT)
<p>
  <br />
  Some text here
  <br />
  Some more text
  <br />
</p>
EOT

doc.search('p > br').map(&:to_html)
# => ["<br>", "<br>", "<br>"]

一旦我们知道我们可以找到它们,就很容易删除特定的:

br_nodes = doc.search('p > br')
br_nodes.first.remove
br_nodes.last.remove
doc.to_html
# => "<p>\n  \n  Some text here\n  <br>\n  Some more text\n  \n</p>\n"

请注意,Nokogiri 删除了它们,但它们的关联文本节点是它们的直接兄弟节点,包含它们的“\n”。浏览器会吞噬这些内容而不显示行尾,但您可能会感到强迫症,因此以下是删除这些内容的方法:

br_nodes = doc.search('p > br')
[br_nodes.first, br_nodes.last].each do |br|
  br.next_sibling.remove
  br.remove
end
doc.to_html
# => "<p>\n  <br>\n  Some more text\n  </p>\n"

【讨论】:

  • 嗨,铁皮人 - 非常感谢你的帮助,最后我设法得到了一个工作版本,继续我所采取的方法 - 我把它贴在这里,这样你就可以看到我设法抓住了自己钓鱼,但现在可以通过更有经验的垂钓者的建议来提高我的技术:)
【解决方案2】:
initial_linebreak_transformer = lambda {|options|
  node = options[:node]
  if node.present? && node.element? && node.name.downcase == 'p'
    first_child = node.children.first
    if first_child.name.downcase == 'br'
      first_child.unlink
      initial_linebreak_transformer.call options
    end
  end
}

【讨论】:

  • 看起来您正在以一种更慢、更困难的方式进行操作。不是检查节点是否存在,而是一个元素,它的名称是'p',告诉 Nokogiri 使用 CSS 或 XPath 选择器查找节点;那时你知道所有这些事情并且可以简单地用那个节点做你想做的事情。让 libXML 执行此操作比为每个节点迭代执行此操作要快得多。我强烈建议运行基准测试来证明/反驳您当前的方法,因为处理大型或复杂 HTML 文档的成本很高。
  • 再次感谢 - 我一定会优先尝试您的方法。我从中得到了基础:github.com/vjt/sanitize-rails/blob/master/example/…,因为我正在使用消毒剂,这是我发现的最相关的代码,它开始寻找一种方法来获得我想要的结果。完全同意最好使用 libXML。希望这是有道理的,再次感谢您的建议。
猜你喜欢
  • 1970-01-01
  • 2012-07-13
  • 1970-01-01
  • 2012-01-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多