Подтвердить что ты не робот

Рубиновый анализ 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"].

Почему это? И все равно, чтобы исправить эту несовместимость (помимо использования строковых ключей с самого начала)?

4b9b3361

Ответ 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