[Please post raw text; my newsreader chokes on whatever you posted...]
Nikolay Pavlov wrote:
I have this XML output:
<response>
<num></num>
<token></token>
<operation id="some id" sid="some sid">
<trans></trans>
<data></data>
</operation>
<operation id="other id" sid="other sid"
<trans></trans>
<data></data>
</operation>
...
</response>
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 = '<response>
<num>v1</num>
<token>v2</token>
<operation id="some id" sid="some sid">
<trans>v3</trans>
<data>v4</data>
</operation>
<operation id="other id" sid="other sid">
<trans></trans>
<data></data>
</operation>
</response>'
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
Test Driven Ajax (on Rails) [Book]
"Test Driven Ajax (on Rails)"
assert_xpath, assert_javascript, & assert_ajax