1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
require 'hpricot' class Parser def self.soap_response_to_hash(xml) xml.gsub!(/\n+/, "") xml.gsub!(/(>)\s*(<)/, '\1\2') doc = Hpricot.XML(xml) return xml_node_to_hash doc.at("//return") end private def self.xml_node_to_hash(node) this_node = {} node.each_child do |child| if child.children.nil? key, value = child.name, nil elsif child.children.size == 1 && child.children.first.text? key, value = child.name, rubylize(child.children.first.raw_string) else key, value = child.name, xml_node_to_hash(child) end current = this_node[key] case current when Array: this_node[key] << value when nil this_node[key] = value else this_node[key] = [current.dup, value] end end return this_node end def self.rubylize(string) case string when "true": true when "false": false else string end end end result = Parser::soap_response_to_hash(xml)
Refactorings
No refactoring yet !
kotrin
August 8, 2009, August 08, 2009 05:49, permalink
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
require 'rubygems' require 'hpricot' class Parse def self.to_hash n h = {} n.each_child do |c| c.respond_to?(:children) ? h[c.name] = c.children.size>1 ? to_hash(c) : c.children[0].name : h[n.name] = c.name end h end end doc = Hpricot.XML xml.gsub(/(>)\s*(<)/, '\1\2').gsub(/\n+/, "") node = doc%'//return' hash = Parse.to_hash node
With ruby you could use REXML's Hash.from_xml, but I really don't like that. The reason for me to write this, was to convert various xml responses from different soap services to a hash. I don't want any namespaces, attributes, etc. Here's an example response:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns2:authenticateResponse xmlns:ns2="http://v1_0.ws.some.namespace/">
<return>
<authenticationValue>
<orderToken>dfgdfg-4356345-sdfsdf-2345234-234</orderToken>
<tokenHash>000111DDD888444777NNNZZZ555000</tokenHash>
<client>dude</client>
</authenticationValue>
<success>true</success>
</return>
</ns2:authenticateResponse>
</soap:Body>
</soap:Envelope>