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.
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
Replace and access values in nested hash/json by path in Ruby
You can make use of Hash.dig
to get the sub-values, it'll keep calling dig
on the result of each step until it reaches the end, and Array
has dig
as well, so when you reach that array things will keep working:
# you said the separator wasn't important, so it can be changed up here
SEPERATOR = '/'.freeze
class Hash
def get_at_path(path)
dig(*steps_from(path))
end
def replace_at_path(path, new_value)
*steps, leaf = steps_from path
# steps is empty in the "name" example, in that case, we are operating on
# the root (self) hash, not a subhash
hash = steps.empty? ? self : dig(*steps)
# note that `hash` here doesn't _have_ to be a Hash, but it needs to
# respond to `[]=`
hash[leaf] = new_value
end
private
# the example hash uses symbols as the keys, so we'll convert each step in
# the path to symbols. If a step doesn't contain a non-digit character,
# we'll convert it to an integer to be treated as the index into an array
def steps_from path
path.split(SEPERATOR).map do |step|
if step.match?(/\D/)
step.to_sym
else
step.to_i
end
end
end
end
and then it can be used as such (hash
contains your sample input):
p hash.get_at_path("phone_numbers/1/number") # => "2342323423"
p hash.get_at_path("phone_numbers/0/type") # => "mobile"
p hash.get_at_path("name") # => "John"
p hash.get_at_path("address/street") # => "street 1"
hash.replace_at_path("phone_numbers/1/number", "123-123-1234")
hash.replace_at_path("phone_numbers/0/type", "cell phone")
hash.replace_at_path("name", "John Doe")
hash.replace_at_path("address/street", "123 Street 1")
p hash.get_at_path("phone_numbers/1/number") # => "123-123-1234"
p hash.get_at_path("phone_numbers/0/type") # => "cell phone"
p hash.get_at_path("name") # => "John Doe"
p hash.get_at_path("address/street") # => "123 Street 1"
p hash
# => {:name=>"John Doe",
# :address=>{:street=>"123 Street 1", :country=>"country1"},
# :phone_numbers=>[{:type=>"cell phone", :number=>"234234"},
# {:type=>"fixed", :number=>"123-123-1234"}]}
Convert a JSON String to a HashMap
In recursive way:
public static Map<String, Object> jsonToMap(JSONObject json) throws JSONException {
Map<String, Object> retMap = new HashMap<String, Object>();
if(json != JSONObject.NULL) {
retMap = toMap(json);
}
return retMap;
}
public static Map<String, Object> toMap(JSONObject object) throws JSONException {
Map<String, Object> map = new HashMap<String, Object>();
Iterator<String> keysItr = object.keys();
while(keysItr.hasNext()) {
String key = keysItr.next();
Object value = object.get(key);
if(value instanceof JSONArray) {
value = toList((JSONArray) value);
}
else if(value instanceof JSONObject) {
value = toMap((JSONObject) value);
}
map.put(key, value);
}
return map;
}
public static List<Object> toList(JSONArray array) throws JSONException {
List<Object> list = new ArrayList<Object>();
for(int i = 0; i < array.length(); i++) {
Object value = array.get(i);
if(value instanceof JSONArray) {
value = toList((JSONArray) value);
}
else if(value instanceof JSONObject) {
value = toMap((JSONObject) value);
}
list.add(value);
}
return list;
}
Using Jackson library:
import com.fasterxml.jackson.databind.ObjectMapper;
Map<String, Object> mapping = new ObjectMapper().readValue(jsonStr, HashMap.class);
How to convert JSON to a Ruby hash
What about the following snippet?
require 'json'
value = '{"val":"test","val1":"test1","val2":"test2"}'
puts JSON.parse(value) # => {"val"=>"test","val1"=>"test1","val2"=>"test2"}
Convert JSON into a Hash
Solved my issues using:
object = self.as_json.with_indifferent_access
# => allowing me to use a symbol key instead of a string
ok_vals = object[:values][:ok].as_json.gsub(/\=\>/, ':')
# => allowing to change json string '{"val1"=>"val1", "val2"=>"val2"}' to '{"val1":"val1", "val2":"val2"}'
ok_vals = JSON.parse(ok_vals)
# => which transform json string to hash {val1: "val1", val2: "val2"}
Feel free to make any suggestions to this code. Thanks for the help.
Change certain value of a JSON object
Convert the raw json string into hash object using JSON#parse
. Change the hash object as you want. Then convert it back to json string using JSON#dump
:
require 'json'
raw_json = '{"num":11,"content":"puss\n","percentage":0}'
h = JSON.parse(raw_json)
h['num'] += 1
JSON.dump(h) # => '{"num":12,"content":"puss\n","percentage":0}'
Convert JSON to Map
I hope you were joking about writing your own parser. :-)
For such a simple mapping, most tools from http://json.org (section java) would work.
For one of them (Jackson https://github.com/FasterXML/jackson-databind/#5-minute-tutorial-streaming-parser-generator), you'd do:
Map<String,Object> result =
new ObjectMapper().readValue(JSON_SOURCE, HashMap.class);
(where JSON_SOURCE is a File, input stream, reader, or json content String)
Related Topics
Rails ( Set_No_Cache Method) Cannot Disable Browser Caching in Safari and Opera
Ruby Variable Name with Double Underscores
Declaring an Integer Range with Step != 1 in Ruby
Why Aren't Global (Dollar-Sign $) Variables Used
How to Remove Non-Printable/Invisible Characters in Ruby
Testing Routes with Subdomain Constraints Using Rspec
How to Get a Selenium/Ruby Bot to Wait Before Performing an Action
What Is the Purpose of 'Kernel'
Changing Songs on Jplayer by Clicking a Link, Hosted on Amazon S3
Storing Passwords for External APIs - Best Practice
Remove Subdomain from String in Ruby
Is Regexp.Last_Match Thread Safe
Missing File in Gem After Build
How to Use Private Submit to Hide from Profile
How to List the Available Variables in an Ruby Erb Template
Handling Iframe with Capybara Ruby
Issues Installing Ruby and Rails and Devkit on Windows 7 X64 - Fix Needed