我正在尝试从<p>
标记
<p>Foo Bar</p> <p>bar bar bar</p> <p>bla</p>
如您所见,<p> </p>
标记之间总是有空格。
问题是在将字符串保存到我的数据库时,空格会创建<br>
标记。
像strip
或gsub
这样的方法只删除节点中的空格,从而导致:
<p>FooBar</p> <p>barbarbar</p> <p>bla</p>
虽然我想:
<p>Foo Bar</p><p>bar bar bar</p><p>bla</p>
我正在使用:
偶尔会有<p>
个标签的子节点产生同样的问题:
示例代码
注意:代码通常在一行中,我重新格式化它,因为否则会无法忍受......
<p>
<p>
<strong>Selling an Appartment</strong>
</p>
<ul>
<li>
<p>beautiful apartment!</p>
</li>
<li>
<p>near the train station</p>
</li>
.
.
.
</ul>
<ul>
<li>
<p>10 minutes away from a shopping mall </p>
</li>
<li>
<p>nice view</p>
</li>
</ul>
.
.
.
</p>
我如何剥去那些白色空间呢?
事实证明,我使用gsub
方法搞砸了,并没有进一步调查gsub
使用regex
的可能性......
简单的解决方案是添加
data = data.gsub(/>\s+</, "><")
它删除了所有不同节点之间的空格...正则表达式!
答案 0 :(得分:1)
这就是我编写代码的方式:
require 'nokogiri'
doc = Nokogiri::HTML::DocumentFragment.parse(<<EOT)
<p>Foo Bar</p> <p>bar bar bar</p> <p>bla</p>
EOT
doc.search('p, ul, li').each { |node|
next_node = node.next_sibling
next_node.remove if next_node && next_node.text.strip == ''
}
puts doc.to_html
结果是:
<p>Foo Bar</p><p>bar bar bar</p><p>bla</p>
打破它:
doc.search('p')
仅查找文档中的<p>
个节点。 Nokogiri从search
返回NodeSet,如果没有匹配则返回nil。代码循环遍历NodeSet,依次查看每个节点。
next_node = node.next_sibling
获取指向当前<p>
节点之后的下一个节点的指针。
next_node.remove if next_node && next_node.text.strip == ''
如果下一个节点不是nil并且在剥离时其文本不为空,则 next_node.remove
从DOM中删除当前next_node
,换句话说,如果节点只有空格。
如果所有文本节点都应从文档中删除,还有其他技术可以仅定位TextNodes。这是有风险的,因为它最终会删除标签之间的所有空白,导致连续的句子和加入的单词,这可能不是你想要的。
答案 1 :(得分:0)
第一个解决方案可以是删除空文本节点,为您的确切情况快速执行此操作可以是:
require 'nokogiri'
doc = Nokogiri::HTML("<p>Foo Bar</p> <p>bar bar bar</p> <p>bla</p>")
doc.css('body').first.children.map{|node| node.to_s.strip}.compact.join
这对于嵌套元素不会起作用,但应该为你提供一条良好的开端。
更新:
您实际上可以通过以下方式进行优化:
require 'nokogiri'
doc = Nokogiri::HTML::DocumentFragment.parse("<p>Foo Bar</p> <p>bar bar bar</p> <p>bla</p>")
doc.children.map{|node| node.to_s.strip}.compact.join
答案 2 :(得分:0)
这里是您可以寻找的所有可能的任务,这些任务在解析输出时处理不必要的空格(包括 unicode 空格)。
html = "<p>A paragraph.<em> </em> <br><br><em>
</em></p><p><em> </em>
</p><p><em>
</em><strong><em>\" Quoted Text \" </em></strong></p>
<ul><li><p>List 1</p></li><li><p>List 2</p></li><li><p>List 3 </p>
<p><br></p><p><br><em> </em><br>
A text content.<br><em><br>
</em></p></li></ul>"
doc = Nokogiri::HTML.fragment(html)
doc.traverse { |node|
# removes any whitespace node
node.remove if node.text.gsub(/[[:space:]]/, '') == ''
# replace mutiple consecutive spaces with single space
node.content = node.text.gsub(/[[:space:]]{2,}/, ' ') if node.text?
}
# Gives you html without any text node including <br> or multiple spaces anywhere in the text of html
puts doc.to_html
# Gives text of html, concatenating li items with a space between them
# By default li items text are concatenated without the space
Nokogiri::HTML(doc.to_html).xpath('//text()').map(&:text).join(' ')
#Output
# "A paragraph. \" Quoted Text \" \n List 1 \n List 2 \n \n List 3 \n A text content. \n \n"
# To Remove newline character '\n'
Nokogiri::HTML(doc.to_html).xpath('//text()').map(&:text).join(' ').gsub(/\n+/,'')
#Output
# "A paragraph. \" Quoted Text \" List 1 List 2 List 3 A text content."
注意:如果您没有在完整的 fragment
文档中使用 html
,那么您可能需要将 traverse
替换为其他函数,例如 {{ 1}}。
答案 3 :(得分:-1)
data.squish做同样的事情并且更具可读性。