110 votes

quel est le meilleur moyen de convertir au format json formaté valeur de la clé de la paire de rubis de hachage avec le symbole de clé?

Je me demande quel est le meilleur moyen de convertir au format json formaté valeur de la clé de la paire de rubis de hachage avec le symbole de la clé : examole:

{ 'user': { 'name': 'foo', 'age': 40, 'location': { 'city' : 'bar', 'state': 'ca' } } }
==> 
{ :user=>{ :name => 'foo', :age =>'40', :location=>{ :city => 'bar', :state=>'ca' } } }

Est-il une méthode d'assistance peuvent faire cela?

267voto

jai Points 1162

à l'aide de l'json gem lors de l'analyse de la chaîne json, vous pouvez passer dans le symbolize_names option. Voir ici: http://flori.github.com/json/doc/index.html (voir sous parse)

par exemple:

>> s ="{\"akey\":\"one\",\"bkey\":\"two\"}"
>> JSON.parse(s,:symbolize_names => true)
=> {:akey=>"one", :bkey=>"two"} 

21voto

frank Points 56

Leventix, je vous remercie pour votre réponse.

Le Maréchal.la charge(le Maréchal.dump(h)) méthode a probablement le plus de l'intégrité des différentes méthodes, car elle préserve la clé d'original de types de manière récursive.

Ce qui est important dans le cas où vous avez un imbriquée de hachage avec un mélange de chaîne et de touches de symbole et que vous souhaitez conserver ce mélange à décoder (par exemple, cela pourrait se produire si votre hash contient vos propres objets personnalisés, en plus de très complexe/imbriquée tiers des objets dont les clés vous ne pouvez pas manipuler/convertir pour quelque raison que ce soit, comme un projet de contrainte de temps).

E. g.:

h = {
      :youtube => {
                    :search   => 'daffy',                 # nested symbol key
                    'history' => ['goofy', 'mickey']      # nested string key
                  }
    }

Méthode 1: JSON.analyser symbolise toutes les clés de manière récursive => Ne permet pas de conserver original mix

JSON.parse( h.to_json, {:symbolize_names => true} )
  => { :youtube => { :search=> "daffy", :history => ["goofy", "mickey"] } } 

Méthode 2: ActiveSupport::JSON.décoder symbolise haut-niveau des clés => Ne permet pas de conserver original mix

ActiveSupport::JSON.decode( ActiveSupport::JSON.encode(h) ).symbolize_keys
  => { :youtube => { "search" => "daffy", "history" => ["goofy", "mickey"] } }

Méthode 3: Maréchal.charge préserve chaîne d'origine/symbole mélange dans le imbriqués les touches. PARFAIT!

Marshal.load( Marshal.dump(h) )
  => { :youtube => { :search => "daffy", "history" => ["goofy", "mickey"] } }

Sauf si il ya un inconvénient que je le sache, je pense Méthode 3 est le chemin à parcourir.

Cheers

5voto

madlep Points 14374

Il n'y a pas quelque chose de construit en faire le tour, mais il n'est pas trop dur à écrire le code pour le faire en utilisant le JSON gem. Il y a un symbolize_keys méthode intégrée dans les Rails si vous l'utilisez, mais cela ne veut pas symboliser les touches de manière récursive comme vous avez besoin.

require 'json'

def json_to_sym_hash(json)
  json.gsub!('\'', '"')
  parsed = JSON.parse(json)
  symbolize_keys(parsed)
end

def symbolize_keys(hash)
  hash.inject({}){|new_hash, key_value|
    key, value = key_value
    value = symbolize_keys(value) if value.is_a?(Hash)
    new_hash[key.to_sym] = value
    new_hash
  }
end

Comme Leventix dit, le JSON gem ne gère que les chaînes entre guillemets doubles (ce qui est techniquement correcte - JSON doit être formaté avec les guillemets). Ce morceau de code n'est propre qu'avant d'essayer de l'analyser.

4voto

Oel Roc Points 21

Méthode récursive:

require 'json'

def JSON.parse(source, opts = {})
  r = JSON.parser.new(source, opts).parse
  r = keys_to_symbol(r) if opts[:symbolize_names]
  return r
end

def keys_to_symbol(h)
  new_hash = {}
  h.each do |k,v|
    if v.class == String || v.class == Fixnum || v.class == Float
      new_hash[k.to_sym] = v
    elsif v.class == Hash
      new_hash[k.to_sym] = keys_to_symbol(v)
    elsif v.class == Array
      new_hash[k.to_sym] = keys_to_symbol_array(v)
    else
      raise ArgumentError, "Type not supported: #{v.class}"
    end
  end
  return new_hash
end

def keys_to_symbol_array(array)
  new_array = []
  array.each do |i|
    if i.class == Hash
      new_array << keys_to_symbol(i)
    elsif i.class == Array
      new_array << keys_to_symbol_array(i)
    else
      new_array << i
    end
  end
  return new_array
end

1voto

Leventix Points 2310

Bien sûr, il y a un json gem, mais qui ne gère que des guillemets doubles.

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