Accessing Deeply Nested Elements
In order to allow conveniently retrieving and changing deeply nested elements
of value
objects the library implements
RFC 6901 (JSON Pointer):
value jv = { {"one", 1}, {"two", 2} };
assert( jv.at("one") == jv.at_pointer("/one") );
jv.at_pointer("/one") = {{"foo", "bar"}};
assert( jv.at("one").at("foo") == jv.at_pointer("/one/foo") );
jv.at_pointer("/one/foo") = {true, 4, "qwerty"};
assert( jv.at("one").at("foo").at(1) == jv.at_pointer("/one/foo/1") );
This is particularly useful when throwing exceptions is undesirable. For example, compare
object* obj = jv.if_object();
if( !obj )
return nullptr;
value* val = obj->if_contains("one");
if( !val )
return nullptr;
obj = val->if_object();
if( !obj )
return nullptr;
val = obj->if_contains("foo");
if( !val )
return nullptr;
array* arr = val->if_array();
if( !arr )
return nullptr;
return arr->if_contains(1);
with
boost::system::error_code ec;
return jv.find_pointer("/one/foo/1", ec);
The library also allows changing and adding deeply nested elements. The
function value::set_at_pointer
traverses the value similarly to
value::at_pointer
, but additionally, it can create missing elements in
certain cases:
value jv;
jv.set_at_pointer("/two/bar/0", 12);
assert( jv.is_object() );
assert( jv.at_pointer("/two").is_object() );
assert( jv.at_pointer("/two/bar").is_array() );
assert( jv.at_pointer("/two/bar/0") == 12 );
The specific behavior is controlled by an optional parameter of type
set_pointer_options
. For example, here’s the same example with
a different option:
set_pointer_options opts;
opts.create_arrays = false;
jv.set_at_pointer("/two/bar/0", 12, opts);
assert( jv.is_object() );
assert( jv.at_pointer("/two").is_object() );
assert( jv.at_pointer("/two/bar").is_object() ); // object, not array
assert( jv.at_pointer("/two/bar/0") == 12 );