Quick Links:

bal | bbl | bdl | bsl

Namespaces

Component bdljsn_json
[Package bdljsn]

Provide an in-memory representation of a JSON document. More...

Namespaces

namespace  bdljsn

Detailed Description

Outline
Purpose:
Provide an in-memory representation of a JSON document.
Classes:
bdljsn::Json representation of a JSON document
bdljsn::JsonArray representation of a JSON object
bdljsn::JsonObject representation of a JSON array
See also:
Component bdljsn_jsonutil, Component bdljsn_jsonnumber, Component bdljsn_jsonnull
Description:
This component provides a value-semantic type, bdljsn::Json, used as an in-memory representation for a JSON document. This component also provides bdljsn::JsonArray and bdljsn::JsonObject types for representing JSON Arrays and Objects respectively.
bdljsn::Json has a close structural similarity to the JSON grammar itself, which at a high-level looks like:
  JSON ::= Object
         | Array
         | String
         | Number
         | Boolean
         | null
Where the Object and Array alternatives can recursively contain JSON. Just like this grammar, a bdljsn::Json is a variant holding either an Object, Array, String, Number, Boolean, or null. These variant selections are respresented by the following types:
  • Object: JsonObject
  • Array: JsonArray
  • String: bsl::string
  • Number: JsonNumber
  • Boolean: bool
  • null: JsonNull
For more details on the JSON grammar see:
Reading and Writing a bdljsn::Json Object:
bdljsn_jsonutil is the recommended facility to write and read bdljsn::Json objects to and from JSON document text.
operator<< overloads are available for all the types. In addition a canonical BDE print method is available for bdljsn::Json, bdljsn::JsonObject, bdljsn::JsonArray bdljsn::JsonNumber and bdljsn::JsonNull.
All bdljsn::Json Objects are Valid JSON Documents:
Every bdljsn::Json represents a (valid) JSON document (bdljsn::Json does not have an "invalid" state). This means writing a bdljsn::Json to a string can only fail if an out-of-memory condition occurs.
Similarly, every JSON document has a bdljsn::Json representation. However, bdljsn::JsonObject represents Objects having only unique member names, meaning that duplicate member names in a JSON document will be ignored (see bdljsn::JsonUtil for more information on how duplicate names are handled when parsing a JSON document). Note that the JSON RFC says that Object member names "SHOULD be unique", and there is no standard behavior for JSON parsers where member names are not unique (typically an in-process respresentation with unique member names is used).
Important Preconditions:
In order to preserve the invariant that all bdljsn::Json objects are valid JSON documents there are some constructors and assignment operations in bdljsn package that have notable preconditions:
operator== and the Definition of Value:
bdljsn::Json type's definition of value (i.e., the behavior for operator==) mirrors comparing the text of two JSON documents where all the white-space is ignored.
Concretely, bdljsn::Json is a variant type, whose definition of equality is derived from the definition of equality of its constituent types. I.e., two bdljsn::Json objects compare equal if they have the same type and the two objects of that type they contain compare equal. The definition of equality for Object, Array, Boolean, string, and JsonNull types are relatively self-explanatory (see respective operator== definitions for details). The definition of equality for JsonNumber is notable: JsonNumber objects define value in terms of the text of the JSON number string they contain. So two JSON numbers having the same numerical value may compare unequal (e.g., "2" and "2.0" and "20e-1" are considered different JsonNumber values!). Note that bdljsn::JsonNumber::isEqual provides a semantic comparison of two numbers (see bdljsn_jsonnumber for more detail).
Usage:
This section illustrates the intended use of this component.
Example 1: Constructor a Basic bdljsn::Json Object:
Most often bdljsn::Json objects will be written and read from JSON text using bdljsn_jsonutil. In this simple example, we demonstrate manually creating the document below and then verify the properties of the resulting object:
  {
      "number": 3.14,
      "boolean": true,
      "string": "text",
      "null": null,
      "array": [ "2.76", true ],
      "object": { "boolean": false }
  }
First, we use bdljsn::Json::makeObject to configure the top level bdljsn::Json object to be a bdljsn::Json object, and use the various manipulators of bdljsn::JsonObject to configure its value:
  using namespace bdldfp::DecimalLiterals;

  bdljsn::Json json;

  json.makeObject();
  json["number"]  = 3.14;
  json["boolean"] = true;
  json["string"]  = "text";
  json["array"].makeArray();
  json["array"].theArray().pushBack(bdljsn::Json(2.76_d64));
  json["array"].theArray().pushBack(bdljsn::Json(true));
  json["object"].makeObject()["boolean"] = false;
Notice that we used operator[] to implicitly create new members of the top-level object. Using json.theObject().insert would be more efficient (see example 2).
Finally, we validate the properties of the resulting object:
  assert(3.14     == json["number"].asDouble());
  assert(true     == json["boolean"].theBoolean());
  assert("text"   == json["string"].theString());
  assert(true     == json["null"].isNull());
  assert(2.76_d64 == json["array"][0].asDecimal64());
  assert(false    == json["object"]["boolean"].theBoolean());
Example 2: More Efficiently Creating a bdljsn::Json:
Example 1 used operator[] to implicitly add members to the Objects. Using operator[] is intuitive but not the most efficient method to add new members to a bdljsn::JsonObject (similar to using operator[] to add elements to an unordered_map). The following code demonstrates a more efficient way to create the same bdljsn::Json representation as example 1:
  using namespace bdldfp::DecimalLiterals;

  bdljsn::Json       json;
  bdljsn::JsonArray  subArray;
  bdljsn::JsonObject subObject;

  json.makeObject();
  json.theObject().insert("number", bdljsn::JsonNumber(3.14));
  json.theObject().insert("boolean", true);
  json.theObject().insert("string", "text");
  json.theObject().insert("null", bdljsn::JsonNull());

  subArray.pushBack(bdljsn::Json(2.76_d64));
  subArray.pushBack(bdljsn::Json(true));
  json.theObject().insert("array", bsl::move(subArray));

  subObject.insert("boolean", false);
  json.theObject().insert("object", bsl::move(subObject));
/**