我有一些HTML:
<p>Lorem ipsum example laoreet. <a href="#">example</a>Cum porttitor</p>
<p>Phasellus <a href="#">gravida tempor example</a> magna</p>
我需要在HTML中出现的文本“example”的任何实例周围换行,除非它在锚标记内。这样就可以了:
<p>Lorem ipsum <span class="something">example</span> laoreet. <a href="#">example</a>Cum porttitor</p>
<p>Phasellus <a href="#">gravida tempor example</a> posuere. Fusce vitae urna eu <span class="something">example</span> magna</p>
我可以使用以下方法选择不在锚标记内的段落内容:
doc.xpath('//p//text()') - doc.xpath('//p//a/text()')
我可以使用以下方法将标签包裹在另一个标签的文本内容周围:
doc.search('div.some-class text()').wrap('<span class="something"></span>')
但是如何在该内容中的文本周围包装标签?
答案 0 :(得分:1)
text()
Xpath选择器也可以用来匹配这样的文字:
Using XPath, How do I select a node based on its text content and value of an attribute?
doc.xpath("//p//text()='example'")
但我认为这不会起作用:
doc.search("div.some-class text()='example'").wrap('<span class="something"></span>')
答案 1 :(得分:1)
你可能不得不在Ruby中操纵有问题的文本节点,然后在文档中replace
使用Nokogiri为你解析的新文本。
doc.xpath('//p/descendant-or-self::node()[name() != "a"]/text()[contains(., "example")]').each do |n|
n.replace(n.content.gsub(/(example)/, '<span class="something">\1</span>'))
end
在这个例子中,我使用了比你更复杂的XPath查询。它选择任何p
元素的所有文本节点后代,除非它们是a
元素的后代,我认为这是你想要的。 (我不知道这对你有好处,试试看。)
回答问题的位是块的内容。在这里,我获取每个文本节点的字符串内容,并使用gsub
创建一个新的标记字符串,其中包含新的span
元素。然后我使用replace
将此片段放入原始文本节点在文档中的位置。 Nokogiri将解析此字符串并添加创建的节点来代替原始文本节点。这在很多方面与the Tin Man’s answer类似,但更具针对性,因为它只涉及使用gsub
并重新解析相关的文本节点。
答案 2 :(得分:0)
我是这样做的:
require 'nokogiri'
doc = Nokogiri::HTML(<<EOT)
<p>Lorem ipsum example sit amet. <a href="#">example</a>Sed porttitor</p>
<p>Phasellus <a href="#">tempor example</a> posuere. Example </p>
EOT
a_tags = doc.search('a')
new_doc = Nokogiri::HTML(
doc.to_html.gsub(
/\b (example) \b/ix,
'<span class="foo">\1</span>'
)
)
new_doc.search('a').each do |a_tag|
a_tag.replace(a_tags.shift)
end
puts new_doc.to_html
# >> </body></html>
# >> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
# >> <html><body>
# >> <p>Lorem ipsum <span class="foo">example</span> sit amet. <a href="#">example</a>Sed porttitor</p>
# >> <p>Phasellus <a href="#">tempor example</a> posuere. <span class="foo">Example</span> </p>
# >> </body></html>
基本上它是这样做的:
a_tags = doc.search('a')
抓取所有现有的<a>
代码以便记住它们。doc
DOM转换回HTML以使用to_html
保持一致性,然后执行全局搜索并替换以包裹<span>
中的所有“示例”实例,然后重新分析它成为一个新的DOM。请注意,我正在使用/\b (example) \b/ix
进行搜索,并使用\1
进行替换。为什么我使用捕获并且标记是供您研究的,但您应该注意到它让我找到并处理“示例”或“示例”。<a>
标记,并用原始版本替换每个标记。这将清除上一步中gsub
所造成的任何损坏。这比我喜欢的更强大,但它也是直截了当的。如果在标签内找到“example”一词,这将会中断。
也许其中一位聪明的XPath人会用更优雅的东西加入。
答案 3 :(得分:0)
以下是我最终的表现:
doc = Nokogiri::HTML(html)
# Select paragraph content that isn't inside an anchor tag
elements = doc.xpath('//p//text()') - doc.xpath('//p//a/text()')
# interate over the elements, wrapping 'phrase' with anchor tag
elements.each do |element|
element.content = element.content.gsub(phrase, "<a href='#' class='glossary-term-link' data-content='#{definition.html_safe}'>#{phrase}</a>")
end
# Fix Nokogiri's lust for escaping angle brackets no matter what
doc.xpath('//body')[0].inner_html.gsub("<", "<").gsub(">", ">")