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