How to Convert JSON to a Hash, Search for and Change a Value

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



Leave a reply



Submit