module MultiXml

def self.parse_binary(binary, entity) #:nodoc:

:nodoc:
TODO: Add support for other encodings
def self.parse_binary(binary, entity) #:nodoc:
  case entity['encoding']
  when 'base64'
    Base64.decode64(binary)
  else
    binary
  end
end

def self.parse_file(file, entity)

def self.parse_file(file, entity)
  f = StringIO.new(Base64.decode64(file))
  f.extend(FileLike)
  f.original_filename = entity['name']
  f.content_type = entity['content_type']
  f
end

def default_parser

to see which are installed if none are loaded.
if any parsers are already loaded, then checks
have loaded and installed. First checks to see
The default parser based on what you currently
def default_parser
  return :libxml if defined?(::LibXML)
  return :nokogiri if defined?(::Nokogiri)
  REQUIREMENT_MAP.each do |(library, parser)|
    begin
      require library
      return parser
    rescue LoadError
      next
    end
  end
end

def parse(xml, options={})

:symbolize_keys :: If true, will use symbols instead of strings for the keys.

Options

Parse an XML string into Ruby.
def parse(xml, options={})
  xml.strip!
  begin
    hash = typecast_xml_value(undasherize_keys(parser.parse(xml))) || {}
  rescue parser.parse_error => error
    raise ParseError, error.to_s, error.backtrace
  end
  hash = symbolize_keys(hash) if options[:symbolize_keys]
  hash
end

def parser

Get the current parser class.
def parser
  return @parser if @parser
  self.parser = self.default_parser
  @parser
end

def parser=(new_parser)

* :rexml
* :nokogiri
* :libxml

Supported by default are:
Set the XML parser utilizing a symbol, string, or class.
def parser=(new_parser)
  case new_parser
  when String, Symbol
    require "multi_xml/parsers/#{new_parser.to_s.downcase}"
    @parser = MultiXml::Parsers.const_get("#{new_parser.to_s.split('_').map{|s| s.capitalize}.join('')}")
  when Class, Module
    @parser = new_parser
  else
    raise "Did not recognize your parser specification. Please specify either a symbol or a class."
  end
end

def symbolize_keys(hash)

def symbolize_keys(hash)
  hash.inject({}) do |result, (key, value)|
    new_key = case key
    when String
      key.to_sym
    else
      key
    end
    new_value = case value
    when Hash
      symbolize_keys(value)
    else
      value
    end
    result[new_key] = new_value
    result
  end
end

def typecast_xml_value(value)

def typecast_xml_value(value)
  case value
  when Hash
    if value['type'] == 'array'
      _, entries = Array.wrap(value.detect{|key, value| key != 'type'})
      if entries.blank? || (value.is_a?(Hash) && c = value[CONTENT_ROOT] && c.blank?)
        []
      else
        case entries
        when Array
          entries.map{|value| typecast_xml_value(value)}
        when Hash
          [typecast_xml_value(entries)]
        else
          raise "can't typecast #{entries.class.name}: #{entries.inspect}"
        end
      end
    elsif value.has_key?(CONTENT_ROOT)
      content = value[CONTENT_ROOT]
      if block = PARSING[value['type']]
        block.arity == 1 ? block.call(content) : block.call(content, value)
      else
        content
      end
    elsif value['type'] == 'string' && value['nil'] != 'true'
      ''
    # blank or nil parsed values are represented by nil
    elsif value.blank? || value['nil'] == 'true'
      nil
    # If the type is the only element which makes it then
    # this still makes the value nil, except if type is
    # a XML node(where type['value'] is a Hash)
    elsif value['type'] && value.size == 1 && !value['type'].is_a?(Hash)
      nil
    else
      xml_value = value.inject({}) do |hash, (key, value)|
        hash[key] = typecast_xml_value(value)
        hash
      end
      # Turn {:files => {:file => #<StringIO>} into {:files => #<StringIO>} so it is compatible with
      # how multipart uploaded files from HTML appear
      xml_value['file'].is_a?(StringIO) ? xml_value['file'] : xml_value
    end
  when Array
    value.map!{|i| typecast_xml_value(i)}
    value.length > 1 ? value : value.first
  when String
    value
  else
    raise "can't typecast #{value.class.name}: #{value.inspect}"
  end
end

def undasherize_keys(params)

def undasherize_keys(params)
  case params
  when Hash
    params.inject({}) do |hash, (key, value)|
      hash[key.to_s.tr('-', '_')] = undasherize_keys(value)
      hash
    end
  when Array
    params.map{|value| undasherize_keys(value)}
  else
    params
  end
end