diff options
author | Jeremy Kemper <jeremy@bitsweat.net> | 2009-03-09 12:39:20 -0700 |
---|---|---|
committer | Jeremy Kemper <jeremy@bitsweat.net> | 2009-03-09 12:39:20 -0700 |
commit | 146511e0181a8c6703dcff7b5236d81b64841dd5 (patch) | |
tree | 758ccbfd4c4492b1a79acefb71a433d4847a979d /activesupport/lib/active_support/xml_mini/libxml.rb | |
parent | a995a738ca10f9bef023689df70d26aad8931b9a (diff) | |
download | rails-146511e0181a8c6703dcff7b5236d81b64841dd5.tar.gz rails-146511e0181a8c6703dcff7b5236d81b64841dd5.tar.bz2 rails-146511e0181a8c6703dcff7b5236d81b64841dd5.zip |
Revert "Revert "XmlMini supports different backend parsers, starting with libxml""
Will change to require a known-working libxml-ruby.
This reverts commit a995a738ca10f9bef023689df70d26aad8931b9a.
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..dd271dc587 --- /dev/null +++ b/activesupport/lib/active_support/xml_mini/libxml.rb @@ -0,0 +1,131 @@ +# = XML Mini Libxml implementation +module ActiveSupport + module XmlMini + extend self + + # Parse an XML Document string into a simple hash using libxml. + # string:: + # XML Document string to parse + def parse(string) + require 'xml/libxml' unless defined? LibXML + + string.strip! + XML.default_keep_blanks = false + + return {} if string.blank? + return XML::Parser.string(string).parse.to_hash + 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)
\ No newline at end of file |