I have a JSON file that may or may not contain a deeply nested key host.provided.default.ip:
{
"host": {
"provided": {
"default": {
"ip": "192.168.0.1"
}
}
}
}
I’d like to return a default value if that key is not defined. One approach would be to use std.objectHas but this gets messy with deeply nested objects:
if std.objectHas(host, "provided") && std.objectHas(host.provided, "default") && std.objectHas(host.provided.default, "ip") then host.provided.default.ip else "127.0.0.1"
Is there a better way of doing this? I tried std.objectHas(host, "provided.default.ip") but this always returns false.
Thanks!
On Thursday, November 15, 2018 at 10:16:44 AM UTC-8, Preston Podaril wrote:
This is the way to do it, you can't do your second example because this is checking for a key called "provided.default.ip" (aka { host: { "provided.default.ip": ..., } }
Good to know. I was wondering if that was what was happening.
I wonder how hard it would be to write a utility function that walks the keys (assuming that keys never contain a . )
you could use a different syntax though, maybe you find this more readable?
if "provided" in host && "default" in host.provided && "ip" in host.provided.default then
.....
Thanks! That’s definitely a lot nicer on the eyes.
On Thursday, November 15, 2018 at 10:33:02 AM UTC-8, dco…@gaikai.com wrote:
I wonder how hard it would be to write a utility function that walks the keys (assuming that keys never contain a
.)
I came up with the following utility function for this:
{
objectHasDeep(o, f)::
local objectHasDeep_(o, ks) =
if ! std.objectHas(o, ks[0]) then
false
else if std.length(ks) == 1 then
true
else
objectHasDeep_(o[ks[0]], ks[1:]);
objectHasDeep_(o, std.split(f, '.')),
}
In my case, it’s more useful for a get style function (e.g. objectGetDeep(host, "provided.default.ip", "127.0.0.1")):
{
objectGetDeep(o, f, default)::
local objectGetDeep_(o, ks) =
if ! std.objectHas(o, ks[0]) then
default
else if std.length(ks) == 1 then
o[ks[0]]
else
objectGetDeep_(o[ks[0]], ks[1:]);
objectGetDeep_(o, std.split(f, '.')),
}
// Returns true if a value exists at specified path and
// false otherwise
objectHasAtPath(obj, path)::
assert std.isObject(obj) == true;
assert std.isArray(path) == true;
if std.length(path) <= 0 then
false
else if std.length(path) == 1 then
std.objectHas(obj, path[0])
else
if !std.objectHas(obj, path[0]) then
false
else
zstd.objectHasAtPath(obj[path[0]], path[1:]) tailstrict,
// Returns value at path or default, if path does not
// exist in the specified obj.
objectValueAtPath(obj, path, default=null)::
assert std.isObject(obj) == true;
assert std.isArray(path) == true;
if std.length(path) <= 0 then
default
else if std.length(path) == 1 then
if std.objectHas(obj, path[0]) then
obj[path[0]]
else
default
else
if !std.objectHas(obj, path[0]) then
default
else
zstd.objectValueAtPath(obj[path[0]], path[1:], default) tailstrict,