使用Nokogiri从空标签中递归清理XML文档?

我有一个嵌套的XML文档,如下所示:

  test description   12345    

我需要删除所有空的XML节点,如

我最终得到了类似的东西:

 doc = Nokogiri::XML::DocumentFragment.parse <<-EOXML  test description   12345    EOXML phone = doc.css("phone") phone.children.each do | child | child.remove if child.inner_text == '' end 

上面的代码只删除了第一个空标记,例如 。 我无法进入嵌套块。 我想我需要一些递归策略。 我仔细阅读了Nokogiri文档,并检查了很多例子,但我还没有找到解决方案。

我怎样才能解决这个问题?

我正在使用Ruby 1.9.3和Nokogiri 1.5.10。

您应该能够使用xpath "/phone//*[not(text())]"找到没有任何文本的所有节点。

 require 'nokogiri' doc = Nokogiri::XML::Document.parse <<-EOXML  test description   12345    EOXML doc.xpath("/phone//*[not(text())]").remove puts doc.to_s.gsub(/\n\s*\n/, "\n") #=>  #=>  #=> test #=> description #=>  #=> 12345 #=>  #=>  

具有不同方法的后来者,希望增加额外的洞察力。 这种方法消除了恼人的额外新行,并为您提供了保留具有值设置属性的空字段的选项。

 require 'nokogiri' doc = Nokogiri::XML::Document.parse <<-EOXML  test description   12345    EOXML def traverse_and_clean(kid) kid.children.map { |child| traverse_and_clean(child) } kid.remove if kid.content.blank? end traverse_and_clean(doc) 

产量

   test description  12345   

如果你发现自己处于一个特殊的情况,需要保留一些具有某些属性设置的空字段。 您所要做的就是稍微更改traverse_and_clean方法:

 def traverse_and_clean(kid) kid.children.map { |child| traverse_and_clean(child) } kid.remove if kid.content.blank? && kid.attributes.blank? end 
 require 'nokogiri' doc = Nokogiri::XML::Document.parse <<-EOXML  test description   12345    EOXML nodes = doc.xpath("//phone//*[not(text())]") nodes.each{|n| n.remove if n.elem? } puts doc 

产量

   test description  12345   

与@ JustinKo的回答类似,仅使用CSS选择器:

 require 'nokogiri' doc = Nokogiri::XML(<  test description   12345    EOT doc.search(':empty').remove puts doc.to_xml 

看看它做了什么:

   test description  12345   

Nokogiri实现了很多jQuery的选择器,所以总是值得看看这些扩展可以做什么。