我有一个嵌套的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的选择器,所以看看这些扩展可以做什么总是值得的