使用nokogiri将嵌套哈希转换为XML
我有很多级别的嵌套哈希,如:
{ :foo => 'bar', :foo1 => { :foo2 => 'bar2', :foo3 => 'bar3', :foo4 => { :foo5 => 'bar5' }}}
我怎样才能将它们转换成这样的XML?:
bar bar2 bar3 bar5
我已经尝试了xml.send
方法,但它将上面嵌套的哈希转换为:
bar
这个怎么样?
class Hash def to_xml map do |k, v| text = Hash === v ? v.to_xml : v "<%s>%s%s>" % [k, text, k] end.join end end h.to_xml #=> "bar bar2 bar3 bar5 "
接受是一个干净的解决方案,但下面确实“使用”Nokogiri从Hash构造XML并对属性进行特殊处理:
require 'nokogiri' def generate_xml(data, parent = false, opt = {}) return if data.to_s.empty? return unless data.is_a?(Hash) unless parent # assume that if the hash has a single key that it should be the root root, data = (data.length == 1) ? data.shift : ["root", data] builder = Nokogiri::XML::Builder.new(opt) do |xml| xml.send(root) { generate_xml(data, xml) } end return builder.to_xml end data.each { |label, value| if value.is_a?(Hash) attrs = value.fetch('@attributes', {}) # also passing 'text' as a key makes nokogiri do the same thing text = value.fetch('@text', '') parent.send(label, attrs, text) { value.delete('@attributes') value.delete('@text') generate_xml(value, parent) } elsif value.is_a?(Array) value.each { |el| # lets trick the above into firing so we do not need to rewrite the checks el = {label => el} generate_xml(el, parent) } else parent.send(label, value) end } end puts generate_xml( {'myroot' => { 'num' => 99, 'title' => 'something witty', 'nested' => { 'total' => [99, 98], '@attributes' => {'foo' => 'bar', 'hello' => 'world'}}, 'anothernest' => { '@attributes' => {'foo' => 'bar', 'hello' => 'world'}, 'date' => [ 'today', {'day' => 23, 'month' => 'Dec', 'year' => {'y' => 1999, 'c' => 21}, '@attributes' => {'foo' => 'blhjkldsaf'}} ] } }}) puts puts puts generate_xml({ 'num' => 99, 'title' => 'something witty', 'nested' => { 'total' => [99, 98], '@attributes' => {'foo' => 'bar', 'hello' => 'world'}}, 'anothernest' => { '@attributes' => {'foo' => 'bar', 'hello' => 'world'}, 'date' => [ 'today', {'day' => [23,24], 'month' => 'Dec', 'year' => {'y' => 1999, 'c' => 21}, '@attributes' => {'foo' => 'blhjkldsaf'}} ] } })
结果XML输出:
99 something witty 99 98 today 23 Dec 1999 21 99 something witty 99 98 today 23 24 Dec 1999 21