From 36dc94a6a1e742848c5a80975b8bf5d216f54022 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Fri, 16 Jun 2006 10:07:13 +0000 Subject: Added Hash.create_from_xml(string) which will create a hash from a XML string and even typecast if possible [DHH] git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@4453 5ecf4fe2-1ee6-0310-87b1-e25e094e27de --- .../active_support/core_ext/hash/conversions.rb | 70 ++++++++++++++++++++++ 1 file changed, 70 insertions(+) (limited to 'activesupport/lib/active_support/core_ext/hash/conversions.rb') diff --git a/activesupport/lib/active_support/core_ext/hash/conversions.rb b/activesupport/lib/active_support/core_ext/hash/conversions.rb index a3270c31ef..ac4a612e49 100644 --- a/activesupport/lib/active_support/core_ext/hash/conversions.rb +++ b/activesupport/lib/active_support/core_ext/hash/conversions.rb @@ -1,4 +1,5 @@ require 'date' +require 'xml_simple' module ActiveSupport #:nodoc: module CoreExtensions #:nodoc: @@ -20,6 +21,10 @@ module ActiveSupport #:nodoc: "binary" => Proc.new { |binary| Base64.encode64(binary) } } + def self.included(klass) + klass.extend(ClassMethods) + end + def to_xml(options = {}) options[:indent] ||= 2 options.reverse_merge!({ :builder => Builder::XmlMarkup.new(:indent => options[:indent]), @@ -70,6 +75,71 @@ module ActiveSupport #:nodoc: end end + + module ClassMethods + def create_from_xml(xml) + # TODO: Refactor this into something much cleaner that doesn't rely on XmlSimple + undasherize_keys(typecast_xml_value(XmlSimple.xml_in(xml, + 'forcearray' => false, + 'forcecontent' => true, + 'keeproot' => true, + 'contentkey' => '__content__') + )) + end + + private + def typecast_xml_value(value) + case value.class.to_s + when "Hash" + if value.has_key?("__content__") + content = translate_xml_entities(value["__content__"]) + case value["type"] + when "integer" then content.to_i + when "boolean" then content == "true" + when "datetime" then ::Time.parse(content).utc + when "date" then ::Date.parse(content) + else content + end + else + value.empty? ? nil : value.inject({}) do |h,(k,v)| + h[k] = typecast_xml_value(v) + h + end + end + when "Array" + value.map! { |i| typecast_xml_value(i) } + case value.length + when 0 then nil + when 1 then value.first + else value + end + else + raise "can't typecast #{value.inspect}" + end + end + + def translate_xml_entities(value) + value.gsub(/</, "<"). + gsub(/>/, ">"). + gsub(/"/, '"'). + gsub(/'/, "'"). + gsub(/&/, "&") + end + + def undasherize_keys(params) + case params.class.to_s + when "Hash" + params.inject({}) do |h,(k,v)| + h[k.to_s.tr("-", "_")] = undasherize_keys(v) + h + end + when "Array" + params.map { |v| undasherize_keys(v) } + else + params + end + end + end end end end -- cgit v1.2.3