如何只获取其中包含其他标记的节点<p>
的文本:
<p>hello my website is <a href="www.website.com">click here</a> <b>test</b></p>
我只想要“hello my website is
”
这就是我的尝试:
begin
node = html_doc.css('p')
node.each do |node|
node.children.remove
end
return (node.nil?) ? '' : node.text
rescue
return ''
end
答案 0 :(得分:1)
更新2 :好的,您正在删除node.children.remove
的所有子项,包括文本节点,建议的解决方案可能如下所示:
# 1. select all <p> nodes
doc.css('p').
# 2. map children, and flatten
map { |node| node.children }.flatten.
# 3. select text nodes only
select { |node| node.text? }.
# 4. get text and join
map { |node| node.text }.join(' ').strip
此示例返回“hello my website is”,但请注意doc.css('p')
als在<p>
标记内找到<p>
个标记。
更新:抱歉,误读了您的问题,您只想“问好我的网站”,请参阅上面的解决方案,原始答案:
不是直接使用nokogiri,但清洁宝石可能是一个选项:https://github.com/rgrove/sanitize/
Sanitize.clean(html, {}) # => " hello my website is click here test "
仅供参考,它在内部使用了nokogiri。
答案 1 :(得分:1)
您的测试用例中没有包含任何与标记交错的有趣文本。
如果您想将<p>Hello <b>World</b>!</p>
转换为"Hello !"
,那么移除孩子就是一种方法。更简单(并且破坏性更小)就是找到所有文本节点并加入它们:
require 'nokogiri'
html = Nokogiri::HTML('<p>Hello <b>World</b>!</p>')
# Find the first paragraph (in this case the only one)
para = html.at('p')
# Find all the text nodes that are children (not descendants),
# change them from nodes into the strings of text they contain,
# and then smush the results together into one big string.
p para.search('text()').map(&:text).join
#=> "Hello !"
如果您想将<p>Hello <b>World</b>!</p>
变为"Hello "
(无感叹号),您可以这样做:
p para.children.first.text # if you know that text is the first child
p para.at('text()').text # if you want to find the first text node
正如@Iwe所示,如果您愿意,可以使用String#strip
方法从结果中删除前导/尾随空格。
答案 2 :(得分:0)
有一种不同的方式可以解决这个问题。而不是去除删除节点,删除这些节点包含的文本:
require 'nokogiri'
doc = Nokogiri::HTML('<p>hello my website is <a href="www.website.com">click here</a> <b>test</b></p>')
text = doc.search('p').map{ |p|
p_text = p.text
a_text = p.at('a').text
p_text[a_text] = ''
p_text
}
puts text
>>hello my website is test
这是一个简单的示例,但我们的想法是找到<p>
标记,然后在其中扫描包含您不想要的文本的标记。对于每个不需要的标签,抓住他们的文本并从周围的文本中删除它。
在示例代码中,您在a_text
分配中有一个不受欢迎的节点列表,循环遍历它们,并迭代删除文本,如下所示:
text = doc.search('p').map{ |p|
p_text = p.text
%w[a].each do |bad_nodes|
bad_nodes_text = p.at(bad_nodes).text
p_text[bad_nodes_text] = ''
end
p_text
}
您返回text
,这是<p>
个节点的调整文本内容数组。