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.

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