使用Nokogiri从空标记中递归清除XML文档



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

<?xml version="1.0"?>
<phone>
  <name>test</name>
  <descr>description</descr>
  <empty/>
  <lines>
    <line>12345</line>
    <css/>
  </lines>
</phone>

我需要删除所有空的XML节点,如<empty/><css/>

我最终得到了这样的东西:

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

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

我该怎么解决这个问题?

我使用的是Ruby 1.9.3和Nokogiri 1.5.10。

一个采用不同方法的后来者,希望增加更多的洞察力。这种方法删除了令人讨厌的额外新行,并为您提供了保留具有设置值的属性的空字段的选项。

require 'nokogiri'
doc = Nokogiri::XML::Document.parse <<-EOXML
<phone>
  <name>test</name>
  <descr>description</descr>
  <empty/>
  <lines>
    <line>12345</line>
    <css/>
  </lines>
</phone>
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)

输出

<?xml version="1.0"?>
<phone>
  <name>test</name>
  <descr>description</descr>
  <lines>
    <line>12345</line>
  </lines>
</phone>

如果您发现自己处于一种特殊的情况,需要保留一些设置了某些属性的空字段。你所要做的就是稍微改变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

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

require 'nokogiri'
doc = Nokogiri::XML::Document.parse <<-EOXML
<phone>
  <name>test</name>
  <descr>description</descr>
  <empty/>
  <lines>
    <line>12345</line>
    <css/>
  </lines>
</phone>
EOXML
doc.xpath("/phone//*[not(text())]").remove
puts doc.to_s.gsub(/ns*n/, "n")
#=> <?xml version="1.0"?>
#=> <phone>
#=>   <name>test</name>
#=>   <descr>description</descr>
#=>   <lines>
#=>     <line>12345</line>
#=>   </lines>
#=> </phone>
require 'nokogiri'
doc = Nokogiri::XML::Document.parse <<-EOXML
<phone>
  <name>test</name>
  <descr>description</descr>
  <empty/>
  <lines>
    <line>12345</line>
    <css/>
  </lines>
</phone>
EOXML
nodes = doc.xpath("//phone//*[not(text())]")
nodes.each{|n| n.remove if n.elem? }
puts doc

输出

<?xml version="1.0"?>
<phone>
  <name>test</name>
  <descr>description</descr>
  <lines>
    <line>12345</line>
  </lines>
</phone>

类似于@JustinKo只使用CSS选择器的答案:

require 'nokogiri'
doc = Nokogiri::XML(<<EOT)
<?xml version="1.0"?>
<phone>
  <name>test</name>
  <descr>description</descr>
  <empty/>
  <lines>
    <line>12345</line>
    <css/>
  </lines>
</phone>
EOT
doc.search(':empty').remove
puts doc.to_xml

看看它做了什么:

<?xml version="1.0"?>
<phone>
  <name>test</name>
  <descr>description</descr>
  <lines>
    <line>12345</line>
  </lines>
</phone>

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

相关内容

  • 没有找到相关文章

最新更新