What's the cleanest way to ignore empty nodes with Nokogiri::XML::Builder
So let's say I have a builder template like the fol开发者_如何学编程lowing:
builder = Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml|
xml.environment do |environment|
environment.title title
environment.feed feed
environment.status status
environment.description description
# many many more
end
end
builder.to_xml
If feed
and description
were nil
, it could output:
<?xml version="1.0" encoding="UTF-8"?>
<environment>
<title>title</title>
<feed/>
<status>status</status>
<description/>
</environment>
I'd rather it ignored the nils altogether. What's the best way of achieving this?
Desired output:
<?xml version="1.0" encoding="UTF-8"?>
<environment>
<title>title</title>
<status>status</status>
</environment>
Current solution:
builder = Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml|
xml.environment do |environment|
environment.title title if title
environment.feed feed if feed
environment.status status if status
environment.description description if description
# many many more
end
end
builder.to_xml
Is there a cleaner way?
Would this be a useful option on Builder#initialize?
builder = Nokogiri::XML::Builder.new(:encoding => 'UTF-8', :empty_nodes => false)
It depends how many fields you really have, but my suggestion is that you're already making a mistake by manually typing in each one.
If order doesn't matter, just use a hash. (otherwise use an OrderedHash)
fields = {
:title => title,
:feed => feed,
:status => status,
:description => description,
# many more
}
builder = Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml|
xml.environment do |environment|
fields.each do |field_name, field_value|
if field_value
environment.send(field_name, field_value)
end
end
end
end
builder.to_xml
seems to work.
It's not pretty, but at least you just have to define your fields and values in one place. Preferably an object method?
I know this question is old and already has an answer, but having just spent a little bit of time figuring this out, the quick solution to this problem (though probably not performant) lies in Nokogiri::XML::Node#traverse
.
Once you've built your document, you'll just need to traverse it once, checking for empty tags and removing them as you go, like so:
builder.doc.traverse do |node|
node.remove if node.element? && node.text == ""
end
Note that #traverse
returns the result of the last operation, so make sure return something (your builder, or your XML string) after you've finished traversing.
精彩评论