Element Access¶
There are many ways elements in a JSON value can be accessed:
- unchecked access via
operator[] - checked access via
at - access with default value via
value - iterators
- JSON pointers
Testing whether a key or index exists before accessing it is also possible, with contains or find (which returns an iterator to the value, or end() if it is not found).
flowchart TD
A["accessing a value"] --> B{"must it exist?"}
B -->|"yes, missing is an error"| C["at() -- throws"]
B -->|"yes, but checking is my job"| D["operator[] -- unchecked"]
B -->|"no, a fallback is fine"| E["value() -- default value"]
A --> F{"just testing first?"}
F -->|"yes"| G["contains() / find()"] Does this key exist?¶
Use contains to test for a key; it does not modify the value and does not throw:
json j = {{"name", "Mary"}, {"address", {{"city", "Berlin"}}}};
j.contains("name"); // true
j.contains("age"); // false
j.contains("city"); // false: contains() only looks at the top level
j["address"].contains("city"); // true
j.contains(json::json_pointer("/address/city")); // true: a JSON pointer tests a nested path in one call
If the value is needed afterwards, find tests and accesses with a single lookup:
if (auto it = j.find("name"); it != j.end())
{
std::cout << *it << '\n';
}
contains also returns true for a key whose value is null; use j.contains("k") && !j["k"].is_null() if a null should count as missing. To read a value with a fallback instead, see value.
operator[] inserts missing keys
Like std::map::operator[], the non-const operator[] adds a null value if the key is missing. Testing a key with it therefore changes the object:
json j = {{"foo", 1}};
bool absent = j["bar"].is_null(); // true, but j is now {"bar": null, "foo": 1}
Use contains/find to test, and at to access a value that must exist (it throws an out_of_range exception otherwise).