Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Extract XmlMini from XmlSimple. [#1474 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
  • Loading branch information...
commit fea8d9d06ffaf85eb9e590ae3ac7cf082ad0c420 1 parent 8d2ca7d
Joseph Anthony Pasquale Holsten josephholsten authored jeremy committed
Showing with 106 additions and 21 deletions.
  1. +106 −21 activesupport/lib/active_support/core_ext/hash/conversions.rb
127 activesupport/lib/active_support/core_ext/hash/conversions.rb
View
@@ -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 @@ def to_xml(options = {})
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

3 comments on commit fea8d9d

Yehuda Katz
Collaborator

Too bad you’re still using REXML :(

Michael Koziarski
Owner

We’d be more than happy to take patches to use alternative reliable parsers guys.

Please sign in to comment.
Something went wrong with that request. Please try again.