module Cardflex module Xml module Serializer require 'rexml/document' unless defined?(REXML::Document) TYPE_NAMES = { "Symbol" => "symbol", "Float" => "number", "BigNum" => "number", "FixNum" => "number" } TYPE_CONVERSIONS = { "symbol" => proc { |sym| sym.to_s }, "number" => proc do |num| str_num = num.to_s if str_num =~ /\.\d$/ str_num += "0" end str_num end } def self.hash_to_xml(hash) root, contents = hash.keys[0], hash.values[0] if contents.is_a? String builder = Builder::XmlMarkup.new builder.tag!(_xml_escape(root)) { |b| b.text! contents } else _to_xml(contents, :root => root) end end def self._to_xml(hash, options={}) raise ArgumentError, "no root specified" unless options[:root] options[:indent] ||= 2 options[:builder] ||= Builder::XmlMarkup.new(:indent => options[:indent]) options[:builder].instruct! unless options.delete(:skip_instruct) root = _xml_escape(options[:root]) options[:builder].tag!(root) do hash.each do |key, value| case value when ::Hash _to_xml(value, options.merge(:root => key, :skip_instruct => true)) else type_name = TYPE_NAMES[value.class.name] formatted_value = type_name ? TYPE_CONVERSIONS[type_name].call(value) : value options[:builder].tag!(_xml_escape(key), formatted_value) end end end end def self._xml_escape(key) dasherized_key = key.to_s.tr('_', '-') if Builder::XChar.respond_to?(:encode) Builder::XChar.encode(dasherized_key) else dasherized_key.to_xs end end end end end