import std.exception : assertThrown; JSONValue subobj = ["b": JSONValue(1.0), "c": JSONValue(2.0)]; JSONValue subarr = [JSONValue(3.0), JSONValue(4.0), JSONValue(null)]; JSONValue obj = ["a": subobj, "b": subarr]; // access nested fields using member access syntax assert(opt(obj).a.b == 1.0); assert(opt(obj).a.c == 2.0); // get can be used with a default value assert(opt(obj).a.c.get(-1.0) == 2.0); // matched path and type assert(opt(obj).a.c.get(null) == null); // mismatched type -> return default value assert(opt(obj).a.d.get(-1.0) == -1.0); // mismatched path -> return default value // explicit existence check assert(!opt(obj).x.exists); assert(!opt(obj).a.x.y.exists); // works for nested missing paths, too // instead of using member syntax, index syntax can be used assert(opt(obj)["a"]["b"] == 1.0); // integer indices work, too assert(opt(obj).b[0] == 3.0); assert(opt(obj).b[1] == 4.0); assert(opt(obj).b[2].exists); assert(opt(obj).b[2] == null); assert(!opt(obj).b[3].exists); // accessing a missing path throws an exception assertThrown(opt(obj).b[3] == 3); // assignments work, too opt(obj).b[0] = 12; assert(opt(obj).b[0] == 12); // assignments to non-existent paths automatically create all missing parents opt(obj).c.d.opDispatch!"e"( 12); assert(opt(obj).c.d.e == 12); // writing to paths with conflicting types will throw assertThrown(opt(obj).c[2] = 12); // writing out of array bounds will also throw assertThrown(opt(obj).b[10] = 12);
Allows safe access of sub paths of a JSONValue.
Missing intermediate values will not cause an error, but will instead just cause the final path node to be marked as non-existent. See the example below for the possbile use cases.