2011-09-25 41 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"}