Menu

Home

hpg

Common JSON library (json-library)

History v 1.0

2015-12-29 New feature: Simple XPath-style access with operator[str_type]:
  • Navigate to an object, array, pair or value by e.g.
    int ival = MyJSON["key1/subkey1[2]/subsubkey[2]"];
2015-12-28 Changed Building requirements:
  • All Solution and Project files now supports Visual Studio 2015
  • Old Visual Studio 2010 files are renamed (appended "_vc10" to projects and solutions)
Support of commentaries in JSON input strings/files:
  • `js::json` does not stop parsing a JSON string/file anymore if it finds comments anymore
  • Comments are simply stripped off the string (pre-parsing) before the
    common parsing will be done.
  • Supported types of comments:
    // ... A line comment <End-Of-Line>
    ... /* Anything between */ ...
    Both comment styles will be stripped off the string before it is parsed.

Getting started

This page gives a brief overview of the library and contains some samples on how to use it.

First of all there are some assumptions and constraints made by the library's class implementation.

To use the library you should be familiar with the JSON format in general.

For details refer to:
- https://de.wikipedia.org/wiki/JavaScript_Object_Notation
- http://json.org/
(The manual itself will not go into much details for that).

To use the library, you need a C++ compiler (supporting C++11 or newer) and link the json-library to your sources (see chapter Samples).
The library is designed to be used as a static linker library, since it uses template classes.

The JSON library is provided as is without any warranties of accurately support
all features the JSON format may allow.

I spent some time to support even the parsing of numbers with fractional and
exponential values and to support special unicode characters given by "\uXXXX".

Restrictions / Limitations

  • \uXXXXis known but not supported yet.
  • Comments are known and will be stripped off before parsing a JSON string/file, but will not be appended if you save it again to a string/file.
  • Only tested with Visual Studio 2010 and 2015
  • Depends on sources of the dtitem-library (also written by myself) see also chapter Bilding the Library)

What's coming next?

  • Better documentation and better english.
  • Publish DataItem Library the JSON library bases on.
  • One of the major next steps I plan, is the support of UTF-8 natively (including \uXXXX).
  • Probably provide a CMakefile.txt for other compilers.
  • Allow an even more confortable way to navigate through the JSON object by using the already existing operator[str_type], but probably with an additional XPATH-like style. To retrieve the value in a complete hierarchical structure by just using something like settings/local/Key.
  • Probably get rid of the depedent DataItem library ;-)

Building the Library

Compilers

To build the library you will need at least Visual Studio 2015 or 2010 (express versions should do).

Other compilers may work, but I didn't test them yet.

If you make the library compile with another compiler, please let me know, drop me a line
and/or send me the makefile together with version of you compiler and system :)

Externals

The SVN repository uses externals referencing the dtitem-library project.
By downloading a snapshot of json-library you will not get these externals. To build, download also a snapshot of
the dtitem library and copy the contents of the dtitem/src folder to json/external.


JSON Objects

In the library a JSON Object is a class of js::json.
All classes used in the library are located in namespace 'js'.

All strings in the library are of type js::str_type.
Whenever the library will support UTF-8 (or even better UTF-16) character encoding strings/files, js::str_type may be changed from std::string to std::wstring, i.e. better use js::str_type instead of std::string.

Creation and Loading

There are several constructors and creation methods available.

One can use e.g. std::string to create an instance of class json or
reading the contents of a file to create it (refer to js::json::from_string(), js::json::from_file()).

Storing and Saving

There are also methods to retrieve a (nicely formatted) string back from
an existing json object or directly save it to a file (refer to js::json::to_string(), js::json::to_file()).

Reading values

To get access to the data values included in a json object, there exists several methods.

The most easy-to-use method is using json::operator[], that allows you to navigate to the object's sub items in such a way you would do with a standard multi-dimensional C++ array (refer to js::json::operator[], js::json::at()).

Another way is to access a container of type object or array is to use the related access methods directly (refer to js::json::object(), js::json::array(), js::json::value()).

Using these methods assumes that you know the exact format of the loaded JSON data.

If you don't, you may iterate the json object by using the related iteration methods and check the name for each sub item manually (refer to js::json::count(), js::json::at(), js::json::name()).

Writing values, adding new items

This is currently not supported and there are no plans to add them in the next
releases.

Exception handling

All constructors and creation methods may throw exceptions.
All thrown exceptions are derived from std::exception.

You should consider to handle std::exception throwings wise.

All manually thrown exceptions are of one of these types:
- js::ex_parser (the string or file parser cannot identify a symbol or wrong JSON format detected)
- js::ex_generator (the json putted in the generator is malformed (should never happen)
- js::ex_conversion (e.g. you want explicitely read an integer but the JSON value points to s string instead)

Technical details

Internally the json class uses a std::shared_ptr<> descendant that holds
the contents of the object.

When copying or assigning a json object to another object or a sub item to another object,
usually only the reference count of those objects will be increased and the data
will not being copied.

Most of the access methods create sub items and return a new instance of a
json object, which makes heavy use of recursion calls internally.

The JSON library is based on the [[DataItem library]] for its internal references, or you
might want to say the DataItem library consists of a type of serialization using the
JSON library.

In fact, I started with the JSON library first for the purpose to have a
easy-to-use serialization format.

After a while I noticed the DataItem library's dt::dtitem class is much more
flexible than the JSON format can be. Nevertheless a JSON parser is a cool
small project :)


Samples

Here are some sample C++ sources, just for given a first impression about the functions.

Refer for details to the complete doxygen documentation as provided.

Including json.h declares all classes and methods in namespace js but
also adds some using statements to export these to the global namespace.

#include "json.h"

create_simple_object

This sample shows how to use the most simple expression "{}" to create a json of type object from. Then it prints out the name() and the count() of sub items (in this case 0).

void create_simple_object()
{
    str_type str = "{}";

    json mobject = json::from_string(str);
    std::cout << "Created a json object from string "
              << "'" << str << "', "
              << "name = " << mobject.name() << ", "
              << "children = " << mobject.count() << std::endl;
}

==> >Created a json object from string '{}', name = object, children = 0

create_simple_array

Identical to the previous sample but uses the expression "[]" to create a json of type array from.

void create_simple_array()
{
    str_type str = "[]";

    json marray = json::from_string(str);
    std::cout << "Created a json object from string "
              << "'" << str << "', "
              << "name = " << marray.name() << ", "
              << "children = " << marray.count() << std::endl;
}

==> >Created a json object from string '[]', name = array, children = 0

create_key_value_pairs

The next one initializes a json instance with type object containing two pairs. Showing also how to use the direct access method operator[]:

void create_key_value_pairs()
{
    str_type str = "{ \"Key1\" : \"Value1\", \"Key2\" : \"Value2\" }";

    json mobject = json::from_string(str);
    std::cout << "Created json object with name = "
              << mobject.name() << ", "
              << "children = " << mobject.count() << std::endl;
    //> ... name = object, children = 2

    json mpair = mobject[0]; // <-- 1st pair 
    std::cout << "First item of object: name = "
              << mpair.name() << ", key = "
              << mpair.key() << std::endl;
    //> ... name = pair, key = Key1

    mpair = mobject[1]; // <-- 2nd pair
    std::cout << "Second item of object: name = "
              << mpair.name() << ", key = "
              << mpair.key() << std::endl;
    //> ... name = pair, key = Key2

    // Shortcuts to retrieve the values by index not
    // using the pair objects

    std::cout << "First pair's value = " 
              << (str_type)mobject[0] // <-- shortcut to value
              << std::endl;
    //> ... value = Value1

    std::cout << "Second pair's value = " 
              << (str_type)mobject[1] // <-- shortcut to value
              << std::endl;
    //> ... value = Value2
}

XPATH-style: object_in_object_xpath

void object_in_object_xpath()
{
    js::str_type s = "{ \"x\" : { \"y\" : 22 } }";

    // an object in an object
    // { "x" : { "y" : 22 } }
    js::json myJSON = json::from_string(s);

    // use xpath expression x/y ==> pair("y" : 22)
    js::str_type xpath("x/y");

    js::json myPair = myJSON[xpath];

    // check that we got a pair
    assert(myPair.name() == js::str_type("pair"));

    // retrieve the value of the pair (use operator int)
    int myIVal = myPair;
    assert(myIVal == 22);

    // or the complete function in one line...
    myIVal = myJSON["x/y"];
    assert(myIVal == 22);
}

XPATH-style: array_in_multiple_objects_xpath

void array_in_multiple_objects_xpath()
{
    js::str_type s = "{ \"x\" : { \"y\" : [ \"a\", true ] } }";

    // an array in an object in an object
    // { "x" : { "y" : [ "a", true, false, null, 234.456 ] } }
    js::json myJSON = json::from_string(s);

    // use xpath expression x/y[1] ==> array value[1] ==> true
    js::str_type xpath("x/y[1]");

    js::json myValue = myJSON[xpath];

    // check that we got the true constant
    assert(myValue.name() == js::str_type("true"));

    // retrieve the value
    bool value = myValue;
    assert(true == value);

    // or the complete function in one line...
    value = myJSON["x/y[1]"];
    assert(true == value);
}

XPATH-style: object_in_array_in_multiple_objects_xpath

void object_in_array_in_multiple_objects_xpath()
{
    js::str_type s = "{ \"x\" : { \"y\" : [ \"a\", { \"KEY\":\"VALUE\", \"One\" : 1 } ] } }";

    // an object in an array in an object in an object
    // { "x" : { "y" : [ "a", { "KEY" : "VALUE", "One" : 1 } ] } }
    js::json myJSON = json::from_string(s);

    // use xpath expression x/y[1]/KEY 
    //    ==> inner object value[ 1 ] 
    //       ==> Pair ("KEY" : "VALUE")
    js::str_type xpath("x/y[1]/KEY");

    js:json myPair = myJSON[xpath];

    // check, that we got the correct object
    assert(myPair.name() == js::str_type("pair"));

    // retrieve the key and value
    js::str_type key   = myPair.key();
    assert(key == js::str_type("KEY"));

    js::str_type value = myPair; // <-- per default this point to a value (if the json object is of type "pair")
    assert(value == js::str_type("VALUE"));

    // or the complete function in one line...
    value = myJSON["x/y[1]/KEY"];
    assert(value == js::str_type("VALUE"));
}