Рубиновый анализ 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"]
.
Почему это? И все равно, чтобы исправить эту несовместимость (помимо использования строковых ключей с самого начала)?
Ответы
Ответ 1
Короче говоря, нет. Подумайте об этом так, хранение символов в JSON - это то же самое, что хранить строки в JSON. Таким образом, вы не можете различать эти два, когда дело доходит до разбора строки JSON. Вы можете, конечно, преобразовать строковые ключи обратно в символы или на самом деле даже построить класс для взаимодействия с JSON, который делает это автоматически, но я бы рекомендовал просто использовать строки.
Но, только ради этого, вот ответы на этот вопрос в предыдущие времена: "/p >
Каков наилучший способ преобразования пары значений json-форматированного ключа в рубиновый хеш с символом как ключ?
ActiveSupport:: JSON декодирует хеш, теряя символы
Или, возможно, HashWithIndifferentAccess
Ответ 2
Генератор 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
Ответ 3
Я решил свою аналогичную проблему с вызовом метода with_indifferent_access на нем
Здесь у меня есть строка json, и мы можем назначить ее переменной s
s = "{\"foo\":{\"bar\":\"cool\"}}"
Итак, теперь я могу разобрать данные с классом JSON и назначить его h
h = JSON.parse(s).with_indifferent_access
Это создаст хэш, который может принять строку или символ в качестве ключа
h[:foo]["bar"]
#=> "cool"
Ответ 4
- Использовать ActiveSupport:: JSON.decode, это позволит вам легче менять json parsers
- Использовать ActiveSupport:: JSON.decode(my_json, symbolize_names: true)
Это будет рекурсивно символизировать все ключи в хеше.
(подтверждено на ruby 2.0)
Ответ 5
Можно изменить все ключи в хеше, чтобы преобразовать их из строки в символ:
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"}
Ответ 6
Вы не можете использовать этот параметр, как этот
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