将json格式化的键值对转换为ruby哈希键的最好方法是什么?
我想知道什么是最好的方式来转换一个JSON格式的键值对ruby散列与符号作为关键:例如:
{ 'user': { 'name': 'foo', 'age': 40, 'location': { 'city' : 'bar', 'state': 'ca' } } } ==> { :user=>{ :name => 'foo', :age =>'40', :location=>{ :city => 'bar', :state=>'ca' } } }
有没有一个辅助方法可以做到这一点?
在parsingjsonstring时使用json gem,你可以在symbolize_names选项中传递。 看到这里: http : //flori.github.com/json/doc/index.html (看下分析)
例如:
>> s ="{\"akey\":\"one\",\"bkey\":\"two\"}" >> JSON.parse(s,:symbolize_names => true) => {:akey=>"one", :bkey=>"two"}
Leventix,谢谢你的回答。
Marshal.load(Marshal.dump(h))方法可能具有各种方法中最完整的方法,因为它recursion地保留了原始的键types。
如果你有一个混合了string和符号键的嵌套散列,并且你希望在解码时保留这个混合(例如,如果你的散列除了高度复杂/嵌套的第三个散列之外还包含你自己的自定义对象,就会发生这种情况 – 由于任何原因(例如项目时间约束)您无法操作/转换键的对象。
例如:
h = { :youtube => { :search => 'daffy', # nested symbol key 'history' => ['goofy', 'mickey'] # nested string key } }
方法1 :JSON.parse – recursion地表示所有的键=>不保留原始混音
JSON.parse( h.to_json, {:symbolize_names => true} ) => { :youtube => { :search=> "daffy", :history => ["goofy", "mickey"] } }
方法2 :ActiveSupport :: JSON.decode – 仅代表顶级密钥=>不保留原始混音
ActiveSupport::JSON.decode( ActiveSupport::JSON.encode(h) ).symbolize_keys => { :youtube => { "search" => "daffy", "history" => ["goofy", "mickey"] } }
方法3 :Marshal.load – 保留嵌套键中的原始string/符号混合。 完善!
Marshal.load( Marshal.dump(h) ) => { :youtube => { :search => "daffy", "history" => ["goofy", "mickey"] } }
除非有缺点,我不知道,我想方法3是要走的路。
干杯
没有任何内容可以实现,但是使用JSON gem编写代码并不难。 如果你使用的是Rails里面有一个symbolize_keys
方法,但是它不象你所需要的recursion符号化键。
require 'json' def json_to_sym_hash(json) json.gsub!('\'', '"') parsed = JSON.parse(json) symbolize_keys(parsed) end def symbolize_keys(hash) hash.inject({}){|new_hash, key_value| key, value = key_value value = symbolize_keys(value) if value.is_a?(Hash) new_hash[key.to_sym] = value new_hash } end
正如Leventix所说,JSON gem只处理双引号string(这在技术上是正确的 – JSON应该用双引号格式化)。 在尝试parsing它之前,这一小段代码会清理干净。
recursion方法:
require 'json' def JSON.parse(source, opts = {}) r = JSON.parser.new(source, opts).parse r = keys_to_symbol(r) if opts[:symbolize_names] return r end def keys_to_symbol(h) new_hash = {} h.each do |k,v| if v.class == String || v.class == Fixnum || v.class == Float new_hash[k.to_sym] = v elsif v.class == Hash new_hash[k.to_sym] = keys_to_symbol(v) elsif v.class == Array new_hash[k.to_sym] = keys_to_symbol_array(v) else raise ArgumentError, "Type not supported: #{v.class}" end end return new_hash end def keys_to_symbol_array(array) new_array = [] array.each do |i| if i.class == Hash new_array << keys_to_symbol(i) elsif i.class == Array new_array << keys_to_symbol_array(i) else new_array << i end end return new_array end
当然,有一个JSONgem ,但只处理双引号。
处理这个问题的另一种方法是使用YAML序列化/反序列化,这也保留了密钥的格式:
YAML.load({test: {'test' => { ':test' => 5}}}.to_yaml) => {:test=>{"test"=>{":test"=>5}}}
这种方法的好处似乎是更适合于REST服务的格式。