Nokogiri 在标签之间替换文本
Nokogiri substituting text between tags
我在执行正则表达式操作时试图区分纯字符串文本和有效的 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('<', '<').gsub('>', '>').gsub('&lt;', '<').gsub('&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
通过使用 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 使用更好的模板构造的方法,但实际上我想说您可以通过以下两种方法之一更快地获得您想要的内容:
- 考虑使用文档片段(例如,
Nokogiri::HTML.fragment(body)
)是否能满足您的需求。这可能需要对您的代码进行更大程度的重构,但您最终得到的可能会更整洁且更易于维护。
- 您可以通过将方法的
body
输入包装在您自己的 HTML 文档模板中来快速取胜,因此 Nokogiri 不会为您做这件事。例如:
def html_parser(body, terms:)
html = "<html><body>#{body}</body></html>"
doc = Nokogiri::HTML(html)
# etc.
后一个选项可以更快地解决您的问题,但代码可能不会那么整洁。
我在执行正则表达式操作时试图区分纯字符串文本和有效的 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('<', '<').gsub('>', '>').gsub('&lt;', '<').gsub('&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
通过使用 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 使用更好的模板构造的方法,但实际上我想说您可以通过以下两种方法之一更快地获得您想要的内容:
- 考虑使用文档片段(例如,
Nokogiri::HTML.fragment(body)
)是否能满足您的需求。这可能需要对您的代码进行更大程度的重构,但您最终得到的可能会更整洁且更易于维护。 - 您可以通过将方法的
body
输入包装在您自己的 HTML 文档模板中来快速取胜,因此 Nokogiri 不会为您做这件事。例如:
def html_parser(body, terms:)
html = "<html><body>#{body}</body></html>"
doc = Nokogiri::HTML(html)
# etc.
后一个选项可以更快地解决您的问题,但代码可能不会那么整洁。