1 require 'libxml'
2
3 # = XmlMini LibXML implementation
4 module ActiveSupport
5 module XmlMini_LibXML #:nodoc:
6 extend self
7
8 # Parse an XML Document string into a simple hash using libxml.
9 # string::
10 # XML Document string to parse
11 def parse(string)
12 if string.blank?
13 {}
14 else
15 LibXML::XML::Parser.string(string.strip).parse.to_hash
16 end
17 end
18 end
19 end
20
21 module LibXML
22 module Conversions
23 module Document
24 def to_hash
25 root.to_hash
26 end
27 end
28
29 module Node
30 CONTENT_ROOT = '__content__'.freeze
31
32 # Convert XML document to hash
33 #
34 # hash::
35 # Hash to merge the converted element into.
36 def to_hash(hash={})
37 node_hash = {}
38
39 # Insert node hash into parent hash correctly.
40 case hash[name]
41 when Array then hash[name] << node_hash
42 when Hash then hash[name] = [hash[name], node_hash]
43 when nil then hash[name] = node_hash
44 else raise "Unexpected error during hash insertion!"
45 end
46
47 # Handle child elements
48 each_child do |c|
49 if c.element?
50 c.to_hash(node_hash)
51 elsif c.text? || c.cdata?
52 node_hash[CONTENT_ROOT] ||= ''
53 node_hash[CONTENT_ROOT] << c.content
54 end
55 end
56
57
58 # Remove content node if it is blank
59 if node_hash.length > 1 && node_hash[CONTENT_ROOT].blank?
60 node_hash.delete(CONTENT_ROOT)
61 end
62
63 # Handle attributes
64 each_attr { |a| node_hash[a.name] = a.value }
65
66 hash
67 end
68 end
69 end
70 end
71
72 LibXML::XML::Document.send(:include, LibXML::Conversions::Document)
73 LibXML::XML::Node.send(:include, LibXML::Conversions::Node)