+1  A: 

Calling Builder::XmlMarkup.new without any indent parameter at all shouldn’t give you any whitespace.

xml = Builder::XmlMarkup.new
xml.outertag do
  xml.list do
    # Some code which loops through a list
  end
end

xml # => <outertag><list></list></outertag>
Matt
A: 

Accepting Matt's answer as it seems the most generally-applicable. However since my situation is an API that outputs XML for every URL, I want something that works across the board.

Here are two solutions for that:

  1. (My current solution) Make a simple plugin that monkey-patches ActionView::TemplateHandlers::Builder to force 0 indentation (as per Matt's answer). Unfortunately, ActionView::TemplateHandlers::Builder is mostly an opaque string of Ruby code that is eval()ed later. Here is my main module, which I include in:

    module MinimalXml
      module Builder
        def self.included(base)
          base.class_eval do
            def compile(template)
              indent = 0
              "_set_controller_content_type(Mime::XML);" +
                "xml = ::Builder::XmlMarkup.new(:indent => #{indent});" +
                "self.output_buffer = xml.target!;" +
                template.source +
                ";xml.target!;"
            end
          end
        end
      end
    end
    
  2. (Probably a future solution.) It occurs to me that a serious XML-based web service needs to process incoming and outgoing XML, to validate it and do whatever else is necessary. That is a good candidate for Rack middleware. So eventually I foresee myself writing a simple Rack middleware layer which will validate the outgoing XML (sounding the alarm if it is invalid, etc.) and then either pretty-print it if in development mode, or compactify it in production.

jhs