<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -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 &lt;joseph@josephholsten.com&gt;
+# Copyright:: Copyright (c) 2008 Joseph Holsten
+# Copyright:: Copyright (c) 2003-2006 Maik Schmidt &lt;contact@maik-schmidt.de&gt;
+# 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] &lt;&lt; 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'   =&gt; false,
-              'forcecontent' =&gt; true,
-              'keeproot'     =&gt; true,
-              'contentkey'   =&gt; '__content__')
-            ))
+            typecast_xml_value(undasherize_keys(XmlMini.parse(xml)))
           end
 
           private</diff>
      <filename>activesupport/lib/active_support/core_ext/hash/conversions.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>8d2ca7dde1993dea6f01ea504e7c1e154a09dbd0</id>
    </parent>
  </parents>
  <author>
    <name>Joseph Holsten</name>
    <email>joseph@josephholsten.com</email>
  </author>
  <url>http://github.com/rails/rails/commit/fea8d9d06ffaf85eb9e590ae3ac7cf082ad0c420</url>
  <id>fea8d9d06ffaf85eb9e590ae3ac7cf082ad0c420</id>
  <committed-date>2008-11-25T18:53:24-08:00</committed-date>
  <authored-date>2008-11-25T18:53:24-08:00</authored-date>
  <message>Extract XmlMini from XmlSimple. [#1474 state:committed]

Signed-off-by: Jeremy Kemper &lt;jeremy@bitsweat.net&gt;</message>
  <tree>fedb1339432985c173ff8ee0b01e527f70e28d63</tree>
  <committer>
    <name>Jeremy Kemper</name>
    <email>jeremy@bitsweat.net</email>
  </committer>
</commit>
