2011-09-25 93 views
50

可以说我有这个哈希:红宝石JSON解析改变哈希键

{ 
    :info => [ 
    { 
     :from => "Ryan Bates", 
     :message => "sup bra", 
     :time => "04:35 AM" 
    } 
    ] 
} 

我可以做hash[:info]调用信息阵列。

现在,当我把它变成JSON(JSON.generate),然后分析它(JSON.parse),我得到这个散列:

{ 
    "info" => [ 
    { 
     "from" => "Ryan Bates", 
     "message" => "sup bra", 
     "time" => "04:35 AM" 
    } 
    ] 
} 

现在,如果我用hash[:info]返回nil,但不如果我使用hash["info"]

这是为什么?无论如何,解决这种不兼容性(除了从一开始就使用字符串键)?

回答

19

总之,没有。以这种方式考虑一下,在JSON中存储符号与在JSON中存储字符串相同。因此,在解析JSON字符串时,您无法区分这两者。当然,您可以将字符串键转换回符号,或者实际上甚至可以构建一个类来与JSON进行交互,这会自动完成此操作,但我会建议使用字符串。

但是,只是为了它的缘故,这里是这个问题的答案以前的时候,它被问:

what is the best way to convert a json formatted key value pair to ruby hash with symbol as key?

ActiveSupport::JSON decode hash losing symbols

或许,HashWithIndifferentAccess

+0

感谢您的链接,但就像你说的,我就用字符串键 – LanguagesNamedAfterCofee

118

的JSON生成器将符号转换为字符串,因为JSON不支持符号。由于JSON密钥都是字符串,因此解析JSON文档将默认生成带有字符串密钥的Ruby哈希。

通过使用symbolize_names选项,您可以告诉解析器使用符号而不是字符串。

例子:

original_hash = {:info => [{:from => "Ryan Bates", :message => "sup bra", :time => "04:35 AM"}]} 
serialized = JSON.generate(original_hash) 
new_hash = JSON.parse(serialized, {:symbolize_names => true}) 

new_hash[:info] 
#=> [{:from=>"Ryan Bates", :message=>"sup bra", :time=>"04:35 AM"}] 

参考:http://www.ruby-doc.org/stdlib-1.9.3/libdoc/json/rdoc/JSON.html#method-i-parse

+0

感谢信息:) – LanguagesNamedAfterCofee

+0

而我认为它是:symbolize_keys now(http://rubydoc.info/gems/multi_json/1.3.2/MultiJson) – Boushley

+9

@Boushley:不,它仍然是'symbolize_names'。我的答案引用了Ruby标准库附带的JSON引擎。您引用了第三方宝石。似乎在轨道4.1中删除 – wyattisimo

2
  1. 请使用ActiveSupport :: JSON.decode,它可以让你交换JSON解析器更容易
  2. 请使用ActiveSupport :: JSON.decode (my_json,symbolize_names:true)

这将递归地表示散列中的所有键。

(经红宝石确认2。0)

+0

? http://edgeguides.rubyonrails.org/upgrading_ruby_on_rails.html#changes-in-json-handling和http://api.rubyonrails.org/classes/ActiveSupport/JSON.html状态选项支持删除 – nruth

4

我解决了我类似的问题与调用它的with_indifferent_access方法

在这里我有一个JSON字符串,我们可以把它分配给变量s

s = "{\"foo\":{\"bar\":\"cool\"}}" 

所以,现在我可以分析数据与JSON类,并将其分配到h

h = JSON.parse(s).with_indifferent_access 

这将产生一个散列,可以接受一个字符串或符号作为关键

h[:foo]["bar"] 
    #=> "cool" 
+0

是否将'with_indifferent_access'添加到通过Rails生态系统中的某些东西“哈希”? – Mark

+1

@马克你是正确的。这里是一个链接http://api.rubyonrails.org/v4.2.5/classes/ActiveSupport/HashWithIndifferentAccess.html –

0

不能使用该选项这样

ActiveSupport::JSON.decode(str_json, symbolize_names: true)

在Rails 4.1或更高版本,ActiveSupport::JSON.decode不再接受 期权哈希MultiJSON。 MultiJSON已达到其使用寿命, 已被删除。

您可以使用symbolize_keys来处理它。

ActiveSupport::JSON.decode(str_json).symbolize_keys 
2

这是可以修改的所有键在哈希将它们从字符串转换为一个符号:

symbol_hash = Hash[obj.map{ |k,v| [k.to_sym, v] }] 

puts symbol_hash[:info] 
# => {"from"=>"Ryan Bates", "message"=>"sup bra", "time"=>"04:35 AM"} 

不幸的是,它不适合嵌套在数组中的哈希工作。你可以,但是,写一个将所有哈希键有点递归方法:

def symbolize_keys(obj) 
    #puts obj.class # Useful for debugging 
    return obj.collect { |a| symbolize_keys(a) } if obj.is_a?(Array) 
    return obj unless obj.is_a?(Hash) 
    return Hash[obj.map{ |k,v| [k.to_sym, symbolize_keys(v)] }] 
end 

symbol_hash = symbolize_keys(hash) 
puts symbol_hash[:info] 
# => {:from=>"Ryan Bates", :message=>"sup bra", :time=>"04:35 AM"}