JSON

The JSON part of orcus consists of a low-level parser class that handles parsing of JSON strings and a document class that stores parsed JSON structures.

There are two approaches to process JSON strings using the orcus library. One approach is to utilize the json_document_tree class to load and populate the JSON structure tree via its load() method and traverse the tree through its get_document_root() method. This approach is ideal if you want a quick way to parse and access the content of a JSON document with minimal effort.

The other approach is to use the low-level json_parser class directly by providing your own handler class to receive callbacks from the parser. This method requires a bit more effort on your part to provide and populate your own data structure, but if you already have a data structure to store the content of JSON, then this approach is ideal. The json_document_tree class internally uses json_parser to parse JSON contents.

Example

Populating a document tree

The following code snippet shows an example of how to populate an instance of json_document_tree from a JSON string, and navigate its content tree afterward.

#include <orcus/json_document_tree.hpp>
#include <orcus/config.hpp>
#include <orcus/pstring.hpp>

#include <cstdlib>
#include <iostream>

using namespace std;

const char* json_string = "{"
"   \"name\": \"John Doe\","
"   \"occupation\": \"Software Engineer\","
"   \"score\": [89, 67, 90]"
"}";

int main()
{
    using node = orcus::json_document_tree::node;

    orcus::json_config config; // Use default configuration.

    orcus::json_document_tree doc;

    // Load JSON string into a document tree.
    doc.load(json_string, config);

    // Root is an object containing three key-value pairs.
    node root = doc.get_document_root();

    vector<orcus::pstring> keys = root.keys();

    for (auto it = keys.begin(), ite = keys.end(); it != ite; ++it)
    {
        orcus::pstring key = *it;
        node value = root.child(key);
        switch (value.type())
        {
            case orcus::json_node_t::string:
                // string value
                cout << key << ": " << value.string_value() << endl;
            break;
            case orcus::json_node_t::array:
            {
                // array value
                cout << key << ":" << endl;

                for (size_t i = 0; i < value.child_count(); ++i)
                {
                    node array_element = value.child(i);
                    cout << "  - " << array_element.numeric_value() << endl;
                }
            }
            break;
            default:
                ;
        }
    }

    return EXIT_SUCCESS;
}

You’ll see the following output when executing this code:

name: John Doe
occupation: Software Engineer
score:
  - 89
  - 67
  - 90

Using the low-level parser

The following code snippet shows how to use the low-level json_parser class by providing an own handler class and passing it as a template argument:

class json_parser_handler
{
public:
    void begin_parse()
    {
        cout << "begin parse" << endl;
    }

    void end_parse()
    {
        cout << "end parse" << endl;
    }

    void begin_array()
    {
        cout << "begin array" << endl;
    }

    void end_array()
    {
        cout << "end array" << endl;
    }

    void begin_object()
    {
        cout << "begin object" << endl;
    }

    void object_key(const char* p, size_t len, bool transient)
    {
        cout << "object key: " << orcus::pstring(p, len) << endl;
    }

    void end_object()
    {
        cout << "end object" << endl;
    }

    void boolean_true()
    {
        cout << "true" << endl;
    }

    void boolean_false()
    {
        cout << "false" << endl;
    }

    void null()
    {
        cout << "null" << endl;
    }

    void string(const char* p, size_t len, bool transient)
    {
        cout << "string: " << orcus::pstring(p, len) << endl;
    }

    void number(double val)
    {
        cout << "number: " << val << endl;
    }
};

int main()
{
    const char* test_code = "{\"key1\": [1,2,3,4,5], \"key2\": 12.3}";
    size_t n = strlen(test_code);

    cout << "JSON string: " << test_code << endl;

    // Instantiate the parser with an own handler.
    json_parser_handler hdl;
    orcus::json_parser<json_parser_handler> parser(test_code, n, hdl);

    // Parse the string.
    parser.parse();

    return EXIT_SUCCESS;
}

Executing this code will generate the following output:

JSON string: {"key1": [1,2,3,4,5], "key2": 12.3}
begin parse
begin object
object key: key1
begin array
number: 1
number: 2
number: 3
number: 4
number: 5
end array
object key: key2
number: 12.3
end object
end parse

Public interface

Parser

template <typename _Handler>
class orcus::json_parser

Low-level JSON parser. The caller must provide a handler class to receive callbacks.

Public Types

typedef _Handler handler_type

Public Functions

json_parser(const char *p, size_t n, handler_type &hdl)

Constructor.

Parameters
  • p -

    pointer to a string stream containing JSON string.

  • n -

    size of the stream.

  • hdl -

    handler class instance.

void parse()

Call this method to start parsing.

Parser handler

class json_parser_handler

Public Functions

void begin_parse()

Called when the parsing begins.

void end_parse()

Called when the parsing ends.

void begin_array()

Called when the opening brace of an array is encountered.

void end_array()

Called when the closing brace of an array is encountered.

void begin_object()

Called when the opening curly brace of an object is encountered.

void object_key(const char *p, size_t len, bool transient)

Called when a key value string of an object is encountered.

Parameters
  • p -

    pointer to the first character of the key value string.

  • len -

    length of the key value string.

  • transient -

    true if the string value is stored in a temporary buffer which is not guaranteed to hold the string value after the end of this callback. When false, the pointer points to somewhere in the JSON stream being parsed.

void end_object()

Called when the closing curly brace of an object is encountered.

void boolean_true()

Called when a boolean ‘true’ keyword is encountered.

void boolean_false()

Called when a boolean ‘false’ keyword is encountered.

void null()

Called when a ‘null’ keyword is encountered.

void string(const char *p, size_t len, bool transient)

Called when a string value is encountered.

Parameters
  • p -

    pointer to the first character of the string value.

  • len -

    length of the string value.

  • transient -

    true if the string value is stored in a temporary buffer which is not guaranteed to hold the string value after the end of this callback. When false, the pointer points to somewhere in the JSON stream being parsed.

void number(double val)

Called when a numeric value is encountered.

Parameters
  • val -

    numeric value.

Document tree

class orcus::json_document_tree

This class stores a parsed JSON document tree structure.

Public Types

typedef json::detail::node node

Public Functions

json_document_tree()
json_document_tree(string_pool &pool)
~json_document_tree()
void load(const std::string &strm, const json_config &config)

Load raw string stream containing a JSON structure to populate the document tree.

Parameters
  • strm -

    stream containing a JSON structure.

  • config -

    configuration object.

void load(const char *p, size_t n, const json_config &config)

Load raw string stream containing a JSON structure to populate the document tree.

Parameters
  • p -

    pointer to the stream containing a JSON structure.

  • n -

    size of the stream.

  • config -

    configuration object.

node get_document_root() const

Get the root node of the document.

Return
root node of the document.

std::string dump() const

Dump the JSON document tree to string.

Return
a string representation of the JSON document tree.

std::string dump_xml() const

Dump the JSON document tree to an XML structure.

Return
a string containing an XML structure representing the JSON content.

struct orcus::json_config

Public Types

enum output_format_type

Values:

none

Output format is not specified.

xml

Output format is XML.

json

Output format is JSON.

check

Special output format used in unit tests to verify content.

Public Functions

json_config()
~json_config()

Public Members

std::string input_path

Path of the JSON file being parsed, in case the JSON string originates from a file. This parameter is required if external JSON files need to be resolved. Otherwise it’s optional.

std::string output_path

Path of the file to which output is written to. Used only from the orcus-json command line tool.

output_format_type output_format

Output format type. Used only from the orcus-json command line tool.

bool preserve_object_order

Control whether or not to preserve the order of object’s child name/value pairs. By definition, JSON’s object is an unordered set of name/value pairs, but in some cases preserving the original order may be desirable.

bool resolve_references

Control whether or not to resolve JSON references to external files.

bool persistent_string_values

When true, the document tree should allocate memory and hold copies of string values in the tree. When false, no extra memory is allocated for string values in the tree and the string values simply point to the original json string stream.

In other words, when this option is set to false, the caller must ensure that the json string stream instance stays alive for the entire life cycle of the document tree.

class orcus::json::detail::node

Each node instance represents a JSON value object stored in the document tree.

Public Functions

node()
node(const node &other)
node(node &&rhs)
~node()
node_t type() const

Get the type of a node.

Return
node type.

size_t child_count() const

Get the number of child nodes if any.

Return
number of child nodes.

std::vector<pstring> keys() const

Get a list of keys stored in a JSON object node.

Return
a list of keys.
Exceptions
  • orcus::json_document_error -

    if the node is not of the object type.

pstring key(size_t index) const

Get the key by index in a JSON object node. This method works only when the preserve object order option is set.

Return
key value.
Parameters
  • index -

    0-based key index.

Exceptions
  • orcus::json_document_error -

    if the node is not of the object type.

  • std::out_of_range -

    if the index is equal to or greater than the number of keys stored in the node.

node child(size_t index) const

Get a child node by index.

Return
child node instance.
Parameters
  • index -

    0-based index of a child node.

Exceptions
  • orcus::json_document_error -

    if the node is not one of the object or array types.

  • std::out_of_range -

    if the index is equal to or greater than the number of child nodes that the node has.

node child(const pstring &key) const

Get a child node by textural key value.

Return
child node instance.
Parameters
  • key -

    textural key value to get a child node by.

Exceptions
  • orcus::json_document_error -

    if the node is not of the object type, or the node doesn’t have the specified key.

node parent() const

Get the parent node.

Return
parent node instance.
Exceptions
  • orcus::json_document_error -

    if the node doesn’t have a parent node which implies that the node is a root node.

pstring string_value() const

Get the string value of a JSON string node.

Return
string value.
Exceptions
  • orcus::json_document_error -

    if the node is not of the string type.

double numeric_value() const

Get the numeric value of a JSON number node.

Return
numeric value.
Exceptions
  • orcus::json_document_error -

    if the node is not of the number type.

node &operator=(const node &other)
uintptr_t identity() const

Return an indentifier of the JSON value object that the node represents. The identifier is derived directly from the memory address of the value object.

Return
identifier of the JSON value object.

Friends

friend orcus::json::detail::node::::orcus::json_document_tree
enum orcus::json::detail::node_t

Values:

unset

node type is not set.

string

JSON string node. A node of this type contains a string value.

number

JSON number node. A node of this type contains a numeric value.

object

JSON object node. A node of this type contains one or more key-value pairs.

array

JSON array node. A node of this type contains one or more child nodes.

boolean_true

JSON boolean node containing a value of ‘true’.

boolean_false

JSON boolean node containing a value of ‘false’.

null

JSON node containing a ‘null’ value.