Nokogiri 在标签之间替换文本

时间:2021-04-28 05:58:44

标签: ruby-on-rails ruby nokogiri

我试图在执行正则表达式操作时区分纯字符串文本和有效的 HTML 标签。

我最初的实现:

def html_parser(body, terms:)
  doc = Nokogiri::HTML(body)
  terms.each do |term|
    doc.xpath('//text()').each do |node|
      dummy = node.add_previous_sibling(Nokogiri::XML::Node.new('dummy', doc))
      dummy.add_previous_sibling(Nokogiri::XML::Text.new(node.to_s.gsub(/\b#{term}\b/, process_term(term)), doc))
      node.remove
      dummy.remove
    end
  end

  doc.at_css('body').children.to_html.gsub('&lt;', '<').gsub('&gt;', '>').gsub('&amp;lt;', '<').gsub('&amp;gt;', '>')
end

html_parser('hello world', terms: ['hello'])
# After performing the operation, the `doc` is wrapping the string inside the `p` tag automatically, which I do not want.
=> '<p>hello world</p>' # this would be some other value, main problem is wrapping with `p` tag.

但是,这对于其他有效的 HTML 标记很有效。

string = '<span>hello world<span>'
html_parser(string, terms: ['hello'])
# works fine

1 个答案:

答案 0 :(得分:1)

通过使用 Nokogiri::Document(),您要求 Nokogiri 根据您传入的内容创建 HTML 文档的表示形式。如果您没有传入完整的 HTML 文档,而是在这里,在片段中,Nokogiri 将您的输入文本包装到自己的模板中——如果您没有任何外部标签,它将添加 <p> 元素。您可以通过在文档上调用 #to_s 来查看:

Nokogiri::HTML('Hello world').to_s

# => <!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\" \"http://www.w3.org/TR/REC-html40/loose.dtd\">\n" +
"<html><body><p>Hello world</p></body></html>"

您可以尝试寻找方法让 Nokogiri 使用更好的模板构造,但我真的会说您可以通过以下两种方法之一更快地获得所需内容:

  1. 考虑使用文档片段(例如,Nokogiri::HTML.fragment(body))是否可以满足您的需求。这可能需要对您的代码进行更大规模的重构,但您最终得到的内容可能更简洁、更易于维护。
  2. 通过将方法的 body 输入包装在您自己的 HTML 文档模板中,您可以快速获胜,因此 Nokogiri 不会为您执行此操作。例如:
def html_parser(body, terms:)
  html = "<html><body>#{body}</body></html>"
  doc = Nokogiri::HTML(html)
  # etc.

后一个选项可以更快地解决您的问题,但代码可能不那么整洁。