[Please post raw text; my newsreader chokes on whatever you posted…]
Nikolay P. wrote:
I have this XML output:
<operation id="other id" sid="other sid"
...
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.