68 votes

Ruby JSON parse changes Hash keys

Disons que j'ai ce Hash :

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

Je peux appeler le tableau d'informations en faisant hash[:info] .

Lorsque je transforme ce fichier en JSON (JSON.generate), puis que je l'analyse (JSON.parse), j'obtiens ce hachage :

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

Maintenant, si j'utilise hash[:info] il renvoie nil mais pas si j'utilise hash["info"] .

Comment cela se fait-il ? Et y a-t-il un moyen de corriger cette incompatibilité (à part l'utilisation de clés de type chaîne de caractères dès le départ) ?

159voto

wyattisimo Points 809

Le générateur JSON convertit les symboles en chaînes de caractères car JSON ne prend pas en charge les symboles. Comme les clés JSON sont toutes des chaînes, l'analyse d'un document JSON produira par défaut un hachage Ruby avec des clés de type chaîne.

Vous pouvez demander à l'analyseur d'utiliser des symboles au lieu de chaînes de caractères en utilisant l'option symbolize_names option.

Exemple :

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"}]

Référence : http://www.ruby-doc.org/stdlib-1.9.3/libdoc/json/rdoc/JSON.html#method-i-parse

25voto

Lee Jarvis Points 7909

En bref, non. Pensez-y de la manière suivante : stocker des symboles dans JSON est la même chose que stocker des chaînes dans JSON. Il est donc impossible de faire la distinction entre les deux lorsqu'il s'agit d'analyser la chaîne JSON. Vous pouvez bien sûr reconvertir les clés des chaînes en symboles, ou même créer une classe pour interagir avec JSON qui le fait automatiquement, mais je recommanderais d'utiliser simplement des chaînes.

Mais, pour le plaisir, voici les réponses à cette question les dernières fois qu'elle a été posée :

Quel est le meilleur moyen de convertir une paire clé-valeur formatée en json en un hash ruby avec un symbole comme clé ?

ActiveSupport::JSON decode hash perdant des symboles

Ou peut-être un HashWithIndifferentAccess

6voto

aaron.v Points 464

J'ai résolu mon problème similaire en appelant la méthode with_indifferent_access.

Ici, j'ai une chaîne json et nous pouvons l'assigner à la variable s

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

Je peux donc maintenant analyser les données avec la classe JSON et les assigner à h

h = JSON.parse(s).with_indifferent_access

Cela produira un hachage qui peut accepter une chaîne de caractères ou un symbole comme clé

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

3voto

Jdfreefly Points 11
  1. Utilisez ActiveSupport::JSON.decode, cela vous permettra d'échanger plus facilement les analyseurs json.
  2. Utiliser ActiveSupport::JSON.decode(my_json, symbolize_names : true)

Cette opération symbolise de manière récursive toutes les clés du hachage.

(confirmé sur ruby 2.0)

2voto

Kathryn Points 1331

Il est possible de modifier toutes les clés d'un hachage pour les convertir d'une chaîne à un symbole :

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"}

Malheureusement, cela ne fonctionne pas pour le hachage imbriqué dans le tableau. Vous pouvez cependant écrire une petite méthode récursive qui convertit toutes les clés de hachage :

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"}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X