Ruby JSON Parse Changes Hash Keys

Ruby JSON parse changes Hash keys

In short, no. Think about it this way, storing symbols in JSON is the same as storing strings in JSON. So you cannot possibly distinguish between the two when it comes to parsing the JSON string. You can of course convert the string keys back into symbols, or in fact even build a class to interact with JSON which does this automagically, but I would recommend just using strings.

But, just for the sake of it, here are the answers to this question the previous times it's been asked:

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

Or perhaps a HashWithIndifferentAccess

How to convert JSON response to hash, and extract specific key and value

You can use select to extract the expected key and value.
Please refer ruby select.

def specific_currency(currency)
@response_body ||= RestClient.get(@weather).body
@hash_response = JSON.parse(@response_body)['rates'].select { |element| element.to_s == currency }
end

Ruby Hash with integer keys changed to string keys

Nothing in JSON as far as I know, but conversion is easy:

json_hash = {"1" => "2" }
integer_hash = Hash[json_hash.map{|k,v|[ k.to_i, v.to_i ]}]
=> {1 => 2}

So, we take all key & value from the initial hash (json_hash), call to_i on them and get them in a new hash (integer_hash).

Even nesting is not blocking. You could do this in a method:

def to_integer_keys(hash)
keys_values = hash.map do |k,v|
if(v.kind_of? Hash)
new_value = to_integer_keys(v) #it's a hash, let's call it again
else
new_value = v.to_i #it's a integer, let's convert
end

[k.to_i, new_value]
end

Hash[keys_values]
end

How to convert JSON to a hash, search for and change a value

I understand your JSON may look like this:

"{\"features\":{\"additional-options\":true},\"values\":{\"lo-value\":34,\"hi-value\":554},\"persons\":[{\"name\":\"john\",\"member\":true,\"current\":false,\"sponsor\":\"pete\",\"profile\":\"\",\"credits\":[\"04\"],\"linked\":[\"philip\",\"guy\"],\"maptools\":[\"crossfit\",\"soccer\",\"running\"]},{\"name\":\"mary\",\"member\":true,\"current\":false,\"sponsor\":\"judy\",\"profile\":\"\",\"credits\":[\"all\"],\"activities\":[\"swimming\",\"cycling\",\"running\"]}],\"data_map\":[1122,3234]}"

I suggest using an OpenStruct to organize your data:

your_struct_name =  JSON.parse(yourJson, object_class: OpenStruct)

Then you get all the things you want. For the operations you show:

#change_key(hash, "features.additional-options", false)
your_struct_name.features['additional-options'] = false
#this one above you set in this hash-like manner because of the '-' in the middle of the key. Otherwise you could just do your_struct_name.features.additional_options = false

#del_from_array(hash, "persons.name=mary.activities", "cycling")
your_struct_name.persons.last.activities.delete('swimming')

# or selecting by name:
your_struct_name.persons.select {|person| person.name == 'mary' }.first.activities.delete('swimming')

#add_to_array(hash, "persons.name=mary.activities", "hockey")
your_struct_name.persons.last.activities << 'hockey'

#del_key(hash, "data_map")
your_struct_name.delete_field('data_map')

#del_key(hash, persons.name=john.profile)
...

#del_key(hash, persons.name=mary.credits)
...

Then, after you make your changes, you can use:

your_struct_name.to_h.to_json

You can also use the method as_json to get a structure very similar to what you showed on the question:

your_struct_name.as_json

OpenStruct is very nice to deal with data that has a changing structure. If you have data that can be "modeled", has a name you can call, has some attributes you can predict, and even methods you will use for this data, I suggest you to create a Class to describe this data, its properties and attributes (it can even inherit from OpenStruct). Then work inside this Class domain, creating a layer of abstraction. This way your code gets a lot more robust and readable. Don't forget to create automatic tests! It saves you a lot of time.

The way you organize and abstract your data, and specially the way you name entities are things that have high impact on code quality.

For further reading see: Object and ActiveData.

keys of a hash that loads from a json string

Returning keys as strings is JSON default behavior. You can override by providing additional symbolize_names argument.

str = '{"mykey": "myvalue"}'
JSON.parse(str)
#=> {"mykey"=>"myvalue"}

JSON.parse(str, {:symbolize_names => true})
#=> {:mykey=>"myvalue"}

As @Matt said, in his comment, if the key happens to have whitespace (eg: my key ), it will key it as- :"my key".



Related Topics



Leave a reply



Submit