views:

174

answers:

1

The default behavior of XML serialization (to_xml) for ActiveRecord objects will emit 'type' and 'nil' attributes that are similar to XML Schema Instance attributes, but aren't set in a XML Namespace.

For example, a model might produce an output like this:

<user>
  <username nil="true" />
  <first-name type="string">Name</first-name>
</user>

Is there anyway to get to_xml to utilize the XML Schema Instance namespace and prefix the attributes and the values?

Using the above example, I'd like to produce the following:

<user xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" xmlns:xs="http://www.w3.org/1999/XMLSchema"&gt;
  <username xsi:nil="true" />
  <first-name xsi:type="xs:string">Name</first-name>
</user>
A: 

I ran into something similar, but when calling #to_xml on a Hash, not on an AR instance.

I came up with this helper:

  #
  # Returns a new Builder::XmlMarkup that'll handle API's to_xml needs
  # Usually you don't need to construct a builder, as to_xml will create one
  # however we need some things modified (adding a namespace, XSD-nillable-compliant-nils
  # and to_xml is too braindead to allow us to alter such behaviors externally
  #
  def api_new_xml_builder
    builder = Builder::XmlMarkup.new(:indent => 2)
    class << builder
      def method_missing(*args, &block)
        @api_seen ||= 0
        @api_seen += 1
        if @api_seen == 1
          # Root element. Needs some decoration
          args[1] ||= {}
          args[1]["xmlns"] = "http://my_company.com/api/schemas/xml"
          args[1]["xmlns:xsi"] = "http://www.w3.org/2001/XMLSchema-instance"
        end
        if args[2].is_a?(Hash) && args[2][:nil] == true
          args[2]["xsi:nil"] = true
        end
        super(*args, &block)
      end
    end
    builder
  end

It's then used like so:

builder = api_new_xml_builder
foo.to_xml(:builder => builder)

Note that I opted to keep the existing nil= and type= attributes, and add my own xsi-prefixed nil, however it's trivial to replace them instead.

minaguib