开发者

What's the cleanest way to ignore empty nodes with Nokogiri::XML::Builder

开发者 https://www.devze.com 2023-02-18 19:35 出处:网络
So let\'s say I have a builder template like the fol开发者_如何学编程lowing: builder = Nokogiri::XML::Builder.new(:encoding => \'UTF-8\') do |xml|

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.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号