bdljsn.txt @PURPOSE: Provide a value-semantic JSON type and supporting utilities @MNEMONIC: Basic Development Library JSoN (bdljsn) @DESCRIPTION: The 'bdljsn' package provides the 'bdljsn::Json' type, found in the 'bdljsn_json' component, which is a value-semantic representation of JSON data. This package also provides facilities for reading and writing 'bdljsn::Json' objects to JSON documents. 'bdljsn::Json' has close structural similarities to the JSON grammar itself, which looks like the following, at a high level: .. JSON ::= Object | Array | String | Number | Boolean | null .. Noting that the 'Object' and 'Array' alternatives can recursively contain 'JSON'. Just like this grammar, the value of a 'bdljsn::Json' object can be an object, array, string, number, boolean, or the null value. Objects and Arrays are represented by the 'bdljsn::JsonObject' and 'bdljsn::JsonArray' types, respectively, and are also provided by the 'bdljsn_json' component. 'bdljsn::JsonObject' is an associative container from strings to 'bdljsn::Json' objects, and 'bdljsn::JsonArray' is a sequence container with 'bdljsn::Json' elements. Strings and booleans are represented with the standard 'bsl::string' and 'bool' types. The singular "null" value is represented by the 'bdljsn::JsonNull' type, which has a single value like 'std::monostate'. Numbers are represented by the 'bdljsn::JsonNumber' type, which has facilities for storing any number that satisfies the JSON number grammar with arbitrary precision. It also provides operations for converting these arbitrary-precision numbers to common finite-precision number vocabulary types like 'int', 'double', and 'bdldfp::Decimal64', and detecting where overflow, underflow, and/or truncation would occur during conversion. Though this package provides several types representing different kinds of JSON values, in general the 'bdljsn::Json' interface is rich enough to be the primary vocabulary type for working with JSON. For example, if the value stored in a 'bdljsn::Json' holds a JSON object, then you can use much of the associative container interface on the 'bdljsn::Json' object directly, e.g., .. void getName(bsl::string *name, const bdljsn::Json& json) // Load to the specified 'name' the "name" member of the specified // 'json'. The behavior is undefined unless 'json' is a JSON object and // has a "name" member that is a string. { // First, verify that the 'json' is a JSON object, and not another // kind of value. assert(json.isObject()); // Then, we can use the subscript operator with string keys, just like a // map. *name = json["name"].theString(); } .. Alternatively, if a 'bdljsn::Json' holds a JSON array, then we can use it like a sequence container, .. bool findWaldo(const bdljsn::Json& json) // Return 'true' if 'json' is an array that contains the string "waldo", // and return 'false' otherwise. { if (!json.isArray()) { return false; // RETURN } for (bsl::size_t i = 0; i != json.size(); ++i) { const bdljsn::Json& element = json[i]; if (!element.isString()) { continue; // CONTINUE } if (element.theString() == "waldo") { return true; // RETURN } } return false; } .. For an example of constructing 'bdljsn::Json' objects, consider the use case where we have a simple representation of an organization chart, which we would like to convert to JSON for printing to standard output: .. struct Employee { // PUBLIC DATA int d_id; bsl::string d_firstName; bsl::string d_lastName; }; struct Team { // PUBLIC DATA Employee d_manager; bsl::vector<Employee> d_members; }; .. We can define utility functions for converting these types to JSON: .. struct Utility { // CLASS METHODS static void toJson(bdljsn::Json *json, const Employee& employee) // Load to the specified 'json' the value of the specified 'employee' // converted to a JSON value. { bdljsn::Json& result = *json; result.makeObject(); result["id"] = employee.d_id; result["firstName"] = employee.d_firstName; result["lastName"] = employee.d_lastName; } static void toJson(bdljsn::Json *json, const Team& team) // Load to the specified 'json' the value of the specified 'team' // converted to a JSON value. { bdljsn::Json& result = *json; result.makeObject(); bdljsn::Json manager; toJson(&manager, team.d_manager); result["manager"] = bsl::move(manager); bdljsn::Json members; members.makeArray(); for (bsl::size_t i = 0; i != team.d_members.size(); ++i) { bdljsn::Json member; toJson(&member, team.d_members[i]); members[i] = bsl::move(member); } result["members"] = bsl::move(members); } }; .. And then we can create a sample 'Team' and print it to standard output using our 'toJson' functions, .. void example() { Employee manager = { 1, "Michael", "Bloomberg" }; Employee employee0 = { 2, "Peter", "Grauer" }; Employee employee1 = { 3, "Tom", "Secunda" }; Team team; team.d_manager = manager; team.d_members.push_back(employee0); team.d_members.push_back(employee1); bdljsn::Json teamAsJson; Utility::toJson(&teamAsJson, team); // The following set of options to 'write' specify that we would prefer // the output to be pretty-printed. bdljsn::WriteOptions options; options.setStyle(bdljsn::WriteStyle::e_PRETTY); int rc = bdljsn::JsonUtil::write(bsl::cout, teamAsJson, options); assert(0 == rc); } .. Then, we can observe the following printed to standard output: .. { "manager": { "id": 1, "firstName": "Michael", "lastName": "Bloomberg" }, "members": [ { "id": 2, "firstName": "Peter", "lastName": "Grauer" }, { "id": 3, "firstName": "Tom", "lastName": "Secunda" } ] } .. /Hierarchical Synopsis /--------------------- The 'bdljsn' package currently has 14 components having 5 levels of physical dependency. The list below shows the hierarchical ordering of the components. The order of components within each level is not architecturally significant, just alphabetical. .. 5. bdljsn_jsonliterals 4. bdljsn_jsonutil 3. bdljsn_json 2. bdljsn_error bdljsn_jsonnumber bdljsn_writeoptions 1. bdljsn_jsonnull bdljsn_jsontype bdljsn_location bdljsn_numberutil bdljsn_readoptions bdljsn_stringutil bdljsn_tokenizer bdljsn_writestyle .. /Component Synopsis /------------------ : 'bdljsn_error': : Provide a description of an error processing a document. : : 'bdljsn_json': : Provide an in-memory representation of a JSON document. : : 'bdljsn_jsonliterals': : Provide user-defined literals for 'bdljsn::Json' objects. : : 'bdljsn_jsonnull': : Provide a type that represents the JSON 'null' value. : : 'bdljsn_jsonnumber': : Provide a value-semantic type representing a JSON number. : : 'bdljsn_jsontype': : Enumerate the set of JSON value types. : : 'bdljsn_jsonutil': : Provide common non-primitive operations on 'Json' objects. : : 'bdljsn_location': : Provide a value-semantic type for location in a JSON document. : : 'bdljsn_numberutil': : Provide utilities converting between JSON text and numeric types. : : 'bdljsn_readoptions': : Provide options for reading a JSON document. : : 'bdljsn_stringutil': : Provide a utility functions for JSON strings. : : 'bdljsn_tokenizer': : Provide a tokenizer for extracting JSON data from a 'streambuf'. : : 'bdljsn_writeoptions': : Provide options for writing a JSON document. : : 'bdljsn_writestyle': : Enumerate the formatting styles for a writing a JSON document.