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
Rails-Like Database Migrations
Programming Technique: How to Create a Simple Card Game
Converting Utc Timestamp to Iso 8601 in Ruby
Count the Number of Lines in a File Without Reading Entire File into Memory
Ruby/Rails CSV Parsing, Invalid Byte Sequence in Utf-8
How to Get Constants Defined by Ruby's Module Class via Reflection
Ruby Loading Config (Yaml) File in Same Dir as Source
How to Read a Password from the Command Line in Ruby
When to Call a "Require" in Rails
Rails Fields_For Form Not Showing Up, Nested Form
Adding a Staging Environment to the Workflow
How to Install Ruby on Rails 3 on Osx
How to Manage Multiple Gemsets and Ruby Versions with Rvm
How to Get Parent Node in Capybara