diff options
Diffstat (limited to 'activesupport/lib/active_support/xml_mini/libxml.rb')
-rw-r--r-- | activesupport/lib/active_support/xml_mini/libxml.rb | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/activesupport/lib/active_support/xml_mini/libxml.rb b/activesupport/lib/active_support/xml_mini/libxml.rb new file mode 100644 index 0000000000..e1549d8c58 --- /dev/null +++ b/activesupport/lib/active_support/xml_mini/libxml.rb @@ -0,0 +1,131 @@ +# = XML Mini Libxml implementation +module ActiveSupport + module XmlMini_LibXML #:nodoc: + extend self + + # Parse an XML Document string into a simple hash using libxml. + # string:: + # XML Document string to parse + def parse(string) + XML.default_keep_blanks = false + + if string.blank? + {} + else + XML::Parser.string(string.strip).parse.to_hash + end + end + + end +end + +module XML + module Conversions + module Document + def to_hash + root.to_hash + end + end + + module Node + CONTENT_ROOT = '__content__' + LIB_XML_LIMIT = 30000000 # Hardcoded LibXML limit + + # Convert XML document to hash + # + # hash:: + # Hash to merge the converted element into. + def to_hash(hash={}) + if text? + raise RuntimeError if content.length >= LIB_XML_LIMIT + hash[CONTENT_ROOT] = content + else + sub_hash = insert_name_into_hash(hash, name) + attributes_to_hash(sub_hash) + if array? + children_array_to_hash(sub_hash) + elsif yaml? + children_yaml_to_hash(sub_hash) + else + children_to_hash(sub_hash) + end + end + hash + end + + protected + + # Insert name into hash + # + # hash:: + # Hash to merge the converted element into. + # name:: + # name to to merge into hash + def insert_name_into_hash(hash, name) + sub_hash = {} + if hash[name] + if !hash[name].kind_of? Array + hash[name] = [hash[name]] + end + hash[name] << sub_hash + else + hash[name] = sub_hash + end + sub_hash + end + + # Insert children into hash + # + # hash:: + # Hash to merge the children into. + def children_to_hash(hash={}) + each { |child| child.to_hash(hash) } + attributes_to_hash(hash) + hash + end + + # Convert xml attributes to hash + # + # hash:: + # Hash to merge the attributes into + def attributes_to_hash(hash={}) + each_attr { |attr| hash[attr.name] = attr.value } + hash + end + + # Convert array into hash + # + # hash:: + # Hash to merge the array into + def children_array_to_hash(hash={}) + hash[child.name] = map do |child| + returning({}) { |sub_hash| child.children_to_hash(sub_hash) } + end + hash + end + + # Convert yaml into hash + # + # hash:: + # Hash to merge the yaml into + def children_yaml_to_hash(hash = {}) + hash[CONTENT_ROOT] = content unless content.blank? + hash + end + + # Check if child is of type array + def array? + child? && child.next? && child.name == child.next.name + end + + # Check if child is of type yaml + def yaml? + attributes.collect{|x| x.value}.include?('yaml') + end + + end + end +end + +XML::Document.send(:include, XML::Conversions::Document) +XML::Node.send(:include, XML::Conversions::Node) |