【问题标题】:How do I remove white space between HTML nodes?如何删除 HTML 节点之间的空白?
【发布时间】:2013-05-01 07:16:37
【问题描述】:

我正在尝试从<p> 标签之间的 HTML 片段中删除空格

<p>Foo Bar</p> <p>bar bar bar</p> <p>bla</p>

如您所见,&lt;p&gt; &lt;/p&gt; 标记之间总是有一个空格。

问题是在将字符串保存到我的数据库时,空格会创建&lt;br&gt; 标签。 stripgsub 之类的方法只删除节点中的空格,导致:

<p>FooBar</p> <p>barbarbar</p> <p>bla</p>

而我想要:

<p>Foo Bar</p><p>bar bar bar</p><p>bla</p>

我正在使用:

  • Nokogiri 1.5.6
  • Ruby 1.9.3
  • 导轨

更新:

偶尔会有&lt;p&gt;Tags的子节点产生同样的问题:之间的空白

示例代码

注意:代码通常在一行中,我重新格式化它,否则将无法忍受......

<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 方法时搞砸了,并没有进一步调查将gsubregex 一起使用的可能性...

简单的解决方案是添加

data = data.gsub(/>\s+</, "><")

它删除了所有不同类型节点之间的空白... Regex ftw!

【问题讨论】:

  • 除了&lt;p&gt; 之外,您的 HTML 是否包含带有嵌入空格的标签,是否也需要去除这些标签?
  • 首先,感谢您重新格式化我的问题,现在更好了 :) 是的,偶尔会有子标签,例如:&lt;ul&gt;&lt;li&gt; 理想情况下应该被剥离......
  • 您能添加一些&lt;ul&gt;&lt;li&gt; 标签的示例吗?此外,展示您正在使用的数据的全面样本也很重要。当我们只看到一个小子集时,很容易想出只处理该场景而不是整个画面的代码。
  • 更新了它,这似乎是合理的......
  • 您是在创建源 HTML 还是它超出了您的控制范围而您正试图清理别人的烂摊子?如果你能控制它,修复 HTML 生成是正确的答案,而且容易得多。

标签: ruby-on-rails ruby ruby-on-rails-3 nokogiri


【解决方案1】:

第一个解决方案可以是删除空文本节点,针对您的具体情况执行此操作的快速方法可以是:

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

【讨论】:

  • 工作就像一个魅力,因为我不需要调整嵌套元素,这对我来说是一个很好的解决方案! :)
  • 很高兴听到它适合您的需求。
  • 这是一种非常低效的方法。随着 HTML 文件大小的增加,它的运行速度会越来越慢,因为它会查看&lt;body&gt; 下方的 EVERY 节点,而不仅仅是所需的节点。
  • 不,不会有任何改进。您仍然从树的顶部开始,遍历每个节点。
  • 我同意,但是当我使用 DocumentFragment.parse 时,文档的内容只是所需的 HTML,因此我想检查每个节点,搜索会增加不必要的延迟。您是否看到我可能忽略了为什么搜索会使其更快的任何原因?
【解决方案2】:

这就是我编写代码的方式:

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')

仅在文档中查找 &lt;p&gt; 节点。 Nokogiri 从search 返回一个NodeSet,如果没有匹配则返回nil。代码在 NodeSet 上循环,依次查看每个节点。

next_node = node.next_sibling

获取指向当前&lt;p&gt; 节点之后的下一个节点的指针。

next_node.remove if next_node && next_node.text.strip == ''

next_node.remove 会从 DOM 中移除当前的 next_node,如果下一个节点不是 nil 并且在剥离时它的文本不是空的,换句话说,如果该节点只有空格。

如果应该从文档中删除所有 TextNode,还有其他技术可以仅定位 TextNode。这是有风险的,因为它最终可能会删除标签之间的所有空格,从而导致连续句子和连词,这可能不是您想要的。

【讨论】:

  • 如果你能检查我更新的问题,我会很高兴......这个问题真的让我很沮丧......
【解决方案3】:

data.squish 做同样的事情并且更具可读性。

【讨论】:

  • String#squish 不会删除 HTML 标签之间的空格
【解决方案4】:

这是您可以寻找的所有可能的任务,这些任务在解析输出时处理不必要的空格(包括 unicode 空格)。

html = "<p>A paragraph.<em>&nbsp; &nbsp;</em> <br><br><em>&nbsp; &nbsp; &nbsp; 
</em></p><p><em>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </em>
</p><p><em>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; 
&nbsp; &nbsp;&nbsp; </em><strong><em>\" Quoted Text \"&nbsp; </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> &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</em><br>
A text content.<br><em><br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </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."

注意:如果您在完整的html 文档中没有使用fragment,那么您可能需要将traverse 替换为search 等其他函数。

【讨论】:

    猜你喜欢
    • 2015-04-09
    • 2012-09-25
    • 2010-10-06
    • 2012-05-23
    • 1970-01-01
    • 2015-08-24
    • 1970-01-01
    • 2021-12-15
    • 1970-01-01
    相关资源
    最近更新 更多