From: Phlip Date: 2007-09-04T03:28:57+09:00 Subject: Re: Need help in parsing REXML::Document [Please post raw text; my newsreader chokes on whatever you posted...] Nikolay Pavlov wrote: > I have this XML output: ... > Could someone point me to the way on how i can get construction like this > one from the XML above: {:num => value, :token => value, :operation => [{:id => value, :sid => value, I get the idea you want a generic system to turn any stereotypical XML to a hash. The XML is too varied to just hard-code the transformation, but the XML doesn't contain advanced features like nodes containing both text and sub-nodes. def git_riddim(node) hash = {} REXML::XPath.each node, '*' do |node| contents = (node.text || '').strip (hash[node.name] ||= []) << (contents.blank? ? git_riddim(node) : node.text) end return hash end def test_recursive_xml_reader xml = ' v1 v2 v3 v4 ' doc = REXML::Document.new(xml) hash = git_riddim(doc) assert_equal({"response"=>[{"token"=>["v2"], "num"=>["v1"], "operation"=>[{"trans"=>["v3"], "data"=>["v4"]}, {"trans"=>[{}], "data"=>[{}]}]}]}), hash end Now here's the head-hurting part. We need arrays to turn into objects if they only contain one element. def reduce_dimensions(hash) return unless hash.kind_of?(Hash) hash.each do |k,v| v.each do |q| reduce_dimensions(q) end hash[k] = *v end end reduce_dimensions(hash) assert_equal({"response"=> {"token"=>"v2", "num"=>"v1", "operation"=>[{"trans"=>"v3", "data"=>"v4"}, {"trans"=>{}, "data"=>{}}]}}, hash) We used * to turn arrays of none or one into nil or an object. Outside of that trick, my code is much more flabby that usual for Hash contortions. Someone might be able to use .inject or something to get it down to fewer lines, in one pass. -- Phlip http://www.oreilly.com/catalog/9780596510657/ "Test Driven Ajax (on Rails)" assert_xpath, assert_javascript, & assert_ajax