aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport
diff options
context:
space:
mode:
authorJoseph Holsten <joseph@josephholsten.com>2008-11-25 18:53:24 -0800
committerJeremy Kemper <jeremy@bitsweat.net>2008-11-25 18:53:24 -0800
commitfea8d9d06ffaf85eb9e590ae3ac7cf082ad0c420 (patch)
treefedb1339432985c173ff8ee0b01e527f70e28d63 /activesupport
parent8d2ca7dde1993dea6f01ea504e7c1e154a09dbd0 (diff)
downloadrails-fea8d9d06ffaf85eb9e590ae3ac7cf082ad0c420.tar.gz
rails-fea8d9d06ffaf85eb9e590ae3ac7cf082ad0c420.tar.bz2
rails-fea8d9d06ffaf85eb9e590ae3ac7cf082ad0c420.zip
Extract XmlMini from XmlSimple. [#1474 state:committed]
Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
Diffstat (limited to 'activesupport')
-rw-r--r--activesupport/lib/active_support/core_ext/hash/conversions.rb127
1 files changed, 106 insertions, 21 deletions
diff --git a/activesupport/lib/active_support/core_ext/hash/conversions.rb b/activesupport/lib/active_support/core_ext/hash/conversions.rb
index fe38fb665b..b0100947d3 100644
--- a/activesupport/lib/active_support/core_ext/hash/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/hash/conversions.rb
@@ -1,23 +1,116 @@
require 'date'
-# Locked down XmlSimple#xml_in_string
-class XmlSimple
- # Same as xml_in but doesn't try to smartly shoot itself in the foot.
- def xml_in_string(string, options = nil)
- handle_options('in', options)
+# = XmlMini
+# This is a derivitive work of XmlSimple 1.0.11
+# Author:: Joseph Holsten <joseph@josephholsten.com>
+# Copyright:: Copyright (c) 2008 Joseph Holsten
+# Copyright:: Copyright (c) 2003-2006 Maik Schmidt <contact@maik-schmidt.de>
+# License:: Distributes under the same terms as Ruby.
+class XmlMini
+ require 'rexml/document'
+ include REXML
- @doc = parse(string)
- result = collapse(@doc.root)
+ CONTENT_KEY = '__content__'
- if @options['keeproot']
- merge({}, @doc.root.name, result)
+ # Parse an XML Document string into a simple hash
+ #
+ # Same as XmlSimple::xml_in but doesn't shoot itself in the foot,
+ # and uses the defaults from ActiveSupport
+ #
+ # string::
+ # XML Document string to parse
+ #
+ def self.parse(string)
+ doc = REXML::Document.new(string)
+ merge_element!({}, doc.root)
+ end
+
+ private
+ # Convert an XML element and merge into the hash
+ #
+ # hash::
+ # Hash to merge the converted element into.
+ # element::
+ # XML element to merge into hash
+ def self.merge_element!(hash, element)
+ merge!(hash, element.name, collapse(element))
+ end
+
+ # Actually converts an XML document element into a data structure.
+ #
+ # element::
+ # The document element to be collapsed.
+ def self.collapse(element)
+ hash = get_attributes(element)
+
+ if element.has_elements?
+ element.each_element {|child| merge_element!(hash, child) }
+ merge_texts!(hash, element) unless empty_content?(element)
else
- result
+ return merge_texts!(hash, element)
end
+ hash
end
- def self.xml_in_string(string, options = nil)
- new.xml_in_string(string, options)
+ # Merge all the texts of an element into the hash
+ #
+ # hash::
+ # Hash to add the converted emement to.
+ # element::
+ # XML element whose texts are to me merged into the hash
+ def self.merge_texts!(hash, element)
+ unless element.has_text?
+ hash
+ else
+ # must use value to prevent double-escaping
+ text_values = element.texts.map {|t| t.value }
+ merge!(hash, CONTENT_KEY, text_values.join)
+ end
+ end
+
+ # Adds a new key/value pair to an existing Hash. If the key to be added
+ # already exists and the existing value associated with key is not
+ # an Array, it will be wrapped in an Array. Then the new value is
+ # appended to that Array.
+ #
+ # hash::
+ # Hash to add key/value pair to.
+ # key::
+ # Key to be added.
+ # value::
+ # Value to be associated with key.
+ def self.merge!(hash, key, value)
+ if hash.has_key?(key)
+ if hash[key].instance_of?(Array)
+ hash[key] << value
+ else
+ hash[key] = [ hash[key], value ]
+ end
+ elsif value.instance_of?(Array)
+ hash[key] = [ value ]
+ else
+ hash[key] = value
+ end
+ hash
+ end
+
+ # Converts the attributes array of an XML element into a hash.
+ # Returns an empty Hash if node has no attributes.
+ #
+ # element::
+ # XML element to extract attributes from.
+ def self.get_attributes(element)
+ attributes = {}
+ element.attributes.each { |n,v| attributes[n] = v }
+ attributes
+ end
+
+ # Determines if a document element has text content
+ #
+ # element::
+ # XML element to be checked.
+ def self.empty_content?(element)
+ element.texts.join.strip.empty?
end
end
@@ -166,15 +259,7 @@ module ActiveSupport #:nodoc:
module ClassMethods
def from_xml(xml)
- require 'xmlsimple'
-
- # TODO: Refactor this into something much cleaner that doesn't rely on XmlSimple
- typecast_xml_value(undasherize_keys(XmlSimple.xml_in_string(xml,
- 'forcearray' => false,
- 'forcecontent' => true,
- 'keeproot' => true,
- 'contentkey' => '__content__')
- ))
+ typecast_xml_value(undasherize_keys(XmlMini.parse(xml)))
end
private