jsoncons is a C++ library for the construction of JavaScript Object Notation (JSON). It supports parsing a JSON file or string into a json
value, building a json
value in C++ code, and serializing a json
value to a file or string. It also provides an API for generating json read and write events in code, somewhat analogously to SAX processing in the XML world.
jsoncons uses some features that are new to C++ 11, including move semantics and the AllocatorAwareContainer concept. It has been tested with MS VC++ 2013, MS VC++ 2015, GCC 4.8, GCC 4.9, GCC 6.2.0 and recent versions of clang. Note that std::regex
isn't fully implemented in GCC 4.8., so jsoncons_ext/jsonpath
regular expression filters aren't supported for that compiler.
The code repository and releases are on github. It is distributed under the Boost Software License
Features:
- Uses the standard C++ input/output streams library
- Supports conversion from and to the standard library sequence and associative containers
- Supports conversion from and to user defined types
- Passes all tests from JSON_checker except
fail1.json
, which is allowed in RFC7159 - Returns the expected results for all tests from JSONTestSuite
- Supports object members sorted alphabetically by name or in original order
- Implements parsing and serializing JSON text in UTF-8 for narrow character strings and streams
- Supports UTF16 (UTF32) encodings with size 2 (size 4) wide characters
- Correctly handles surrogate pairs in \uXXXX escape sequences
- Supports event based JSON parsing and serializing with user defined input and output handlers
- Accepts and ignores single line comments that start with //, and multi line comments that start with /* and end with */
- Parses files with duplicate names but uses only the last entry
- Supports optional escaping of the solidus (/) character
- Supports Nan, Inf and -Inf replacement
- Supports reading a sequence of JSON texts from a stream
- Supports optional escaping of non-ascii UTF-8 octets
- Supports conversion from and to user defined types
- Handles JSON texts of arbitrarily large depth of nesting, a limit can be set if desired
Extensions:
- The csv extension supports reading (writing) JSON values from (to) CSV files
- The jsonpath extension supports search using Stefan Goessner's JsonPath. It also supports search and replace using JsonPath expressions.
- The binary extension supports encoding to and decoding from the MessagePack binary serialization format.
As the jsoncons
library has evolved, names have sometimes changed. To ease transition, jsoncons deprecates the old names but continues to support many of them. See the deprecated list for the status of old names. The deprecated names can be suppressed by defining macro JSONCONS_NO_DEPRECATED
, which is recommended for new code.
json_benchmarks provides some measurements about how jsoncons
compares to other json
libraries.
Results for JSONTestSuite and JSON_checker tests may be found here.
The jsoncons library is header-only: it consists solely of header files containing templates and inline functions, and requires no separately-compiled library binaries when linking. It has no dependence on other libraries. The accompanying test suite uses boost, but not the library itself.
To install the jsoncons library, download the zip file, unpack the release, under src
find the directory jsoncons
, and copy it to your include
directory. If you wish to use extensions, copy the jsoncons_ext
directory as well.
#include <iostream>
#include <jsoncons/json.hpp>
// For convenience
using jsoncons::json;
int main()
{
json color_spaces = json::array();
color_spaces.add("sRGB");
color_spaces.add("AdobeRGB");
color_spaces.add("ProPhoto RGB");
json image_sizing; // empty object
image_sizing["Resize To Fit"] = true; // a boolean
image_sizing["Resize Unit"] = "pixels"; // a string
image_sizing["Resize What"] = "long_edge"; // a string
image_sizing["Dimension 1"] = 9.84; // a double
json file_export;
// create "File Format Options" as an object and put "Color Spaces" in it
file_export["File Format Options"]["Color Spaces"] = std::move(color_spaces);
file_export["Image Sizing"] = std::move(image_sizing);
std::cout << "(1)\n" << pretty_print(file_export) << "\n\n";
const json& val = file_export["Image Sizing"];
std::cout << "(2) " << "Dimension 1 = " << val["Dimension 1"].as<double>() << "\n\n";
std::cout << "(3) " << "Dimension 2 = " << val.get_with_default("Dimension 2","n/a") << "\n";
}
Output:
(1)
{
"File Format Options": {
"Color Spaces": ["sRGB","AdobeRGB","ProPhoto RGB"]
},
"Image Sizing": {
"Dimension 1": 9.84,
"Resize To Fit": true,
"Resize Unit": "pixels",
"Resize What": "long_edge"
}
}
(2) Dimension 1 = 9.84
(3) Dimension 2 = n/a
For a quick guide, see the article jsoncons: a C++ library for json construction. Consult the wiki for the latest documentation, tutorials and roadmap.
CMake is a cross-platform build tool that generates makefiles and solutions for the compiler environment of your choice. On Windows you can download a Windows Installer package. On Linux it is usually available as a package, e.g., on Ubuntu,
sudo apt-get install cmake
Instructions for building the test suite with CMake may be found in
jsoncons/test_suite/build/cmake/README.txt
Instructions for building the examples with CMake may be found in
jsoncons/examples/build/cmake/README.txt
The jsoncons library provides a basic_json
class template, which is the generalization of a json
value for different character types, different policies for ordering name-value pairs, etc.
typedef basic_json<char,
JsonTraits = json_traits<char>,
Allocator = std::allocator<char>> json;
The library includes four instantiations of basic_json
:
-
json constructs a narrow character json value that sorts name-value members alphabetically
-
ojson constructs a narrow character json value that preserves the original name-value insertion order
-
wjson constructs a wide character json value that sorts name-value members alphabetically
-
owjson constructs a wide character json value that preserves the original name-value insertion order
try
{
json val = json::parse("[1,2,3,4,]");
}
catch(const std::exception& e)
{
std::cout << e.what() << std::endl;
}
Output:
Extra comma at line 1 and column 10
json j = json::array{1,2,3,4};
for (auto val : book.array_range())
{
std::cout << val << std::endl;
}
json book = json::object{
{"author", "Haruki Murakami"},
{"title", "Kafka on the Shore"},
{"price", 25.17}
};
for (const auto& kvp : book.object_range())
{
std::cout << kvp.key() << "="
<< kvp.value() << std::endl;
}
json a = json::make_array<3>(4, 3, 2, 0.0);
double val = 1.0;
for (size_t i = 0; i < a.size(); ++i)
{
for (size_t j = 0; j < a[i].size(); ++j)
{
for (size_t k = 0; k < a[i][j].size(); ++k)
{
a[i][j][k] = val;
val += 1.0;
}
}
}
std::cout << pretty_print(a) << std::endl;
Output:
[
[
[1.0,2.0],
[3.0,4.0],
[5.0,6.0]
],
[
[7.0,8.0],
[9.0,10.0],
[11.0,12.0]
],
[
[13.0,14.0],
[15.0,16.0],
[17.0,18.0]
],
[
[19.0,20.0],
[21.0,22.0],
[23.0,24.0]
]
]
See Arrays for details
std::vector<int> v{1, 2, 3, 4};
json j(v);
std::cout << "(1) "<< j << std::endl;
std::deque<int> d = j.as<std::deque<int>>();
Output:
(1) [1,2,3,4]
std::map<std::string,int> m{{"one",1},{"two",2},{"three",3}};
json j(m);
std::cout << "(1) " << j << std::endl;
std::unordered_map<std::string,int> um = j.as<std::unordered_map<std::string,int>>();
Output:
(1) {"one":1,"three":3,"two":2}
struct book
{
std::string author;
std::string title;
double price;
};
namespace jsoncons
{
template<class Json>
struct json_type_traits<Json, book>
{
// Implement static functions is, as and to_json
};
}
book book1{"Haruki Murakami", "Kafka on the Shore", 25.17};
book book2{"Charles Bukowski", "Women: A Novel", 12.0};
std::vector<book> v{book1, book2};
json j = v;
std::list<book> l = j.as<std::list<book>>();
See Type Extensibility for details.
You can rename object member names with the built in filter rename_name_filter
#include <sstream>
#include <jsoncons/json.hpp>
#include <jsoncons/json_filter.hpp>
using namespace jsoncons;
int main()
{
std::string s = R"({"first":1,"second":2,"fourth":3,"fifth":4})";
json_serializer serializer(std::cout);
// Filters can be chained
rename_name_filter filter2("fifth", "fourth", serializer);
rename_name_filter filter1("fourth", "third", filter2);
// A filter can be passed to any function that takes
// a json_input_handler ...
std::cout << "(1) ";
std::istringstream is(s);
json_reader reader(is, filter1);
reader.read();
std::cout << std::endl;
// or a json_output_handler
std::cout << "(2) ";
ojson j = ojson::parse(s);
j.write(filter1);
std::cout << std::endl;
}
Output:
(1) {"first":1,"second":2,"third":3,"fourth":4}
(2) {"first":1,"second":2,"third":3,"fourth":4}
Or define and use your own filters. See json_filter for details.
The binary
extension supports encoding to and decoding from the MessagePack binary serialization format.
#include <jsoncons/json.hpp>
#include <jsoncons_ext/binary/message_pack.hpp>
using namespace jsoncons;
using namespace jsoncons::binary;
int main()
{
ojson j1;
j1["zero"] = 0;
j1["one"] = 1;
j1["two"] = 2;
j1["null"] = null_type();
j1["true"] = true;
j1["false"] = false;
j1["max int64_t"] = (std::numeric_limits<int64_t>::max)();
j1["max uint64_t"] = (std::numeric_limits<uint64_t>::max)();
j1["min int64_t"] = (std::numeric_limits<int64_t>::min)();
j1["max int32_t"] = (std::numeric_limits<int32_t>::max)();
j1["max uint32_t"] = (std::numeric_limits<uint32_t>::max)();
j1["min int32_t"] = (std::numeric_limits<int32_t>::min)();
j1["max int16_t"] = (std::numeric_limits<int16_t>::max)();
j1["max uint16_t"] = (std::numeric_limits<uint16_t>::max)();
j1["min int16_t"] = (std::numeric_limits<int16_t>::min)();
j1["max int8_t"] = (std::numeric_limits<int8_t>::max)();
j1["max uint8_t"] = (std::numeric_limits<uint8_t>::max)();
j1["min int8_t"] = (std::numeric_limits<int8_t>::min)();
j1["max double"] = (std::numeric_limits<double>::max)();
j1["min double"] = -(std::numeric_limits<double>::max)();
j1["max float"] = (std::numeric_limits<float>::max)();
j1["zero float"] = 0.0;
j1["min float"] = -(std::numeric_limits<float>::max)();
j1["Key too long for small string optimization"] = "String too long for small string optimization";
std::vector<uint8_t> v = encode_message_pack(j1);
ojson j2 = decode_message_pack<ojson>(v);
std::cout << pretty_print(j2) << std::endl;
}
Output:
{
"zero": 0,
"one": 1,
"two": 2,
"null": null,
"true": true,
"false": false,
"max int64_t": 9223372036854775807,
"max uint64_t": 18446744073709551615,
"min int64_t": -9223372036854775808,
"max int32_t": 2147483647,
"max uint32_t": 4294967295,
"min int32_t": -2147483648,
"max int16_t": 32767,
"max uint16_t": 65535,
"min int16_t": -32768,
"max int8_t": 127,
"max uint8_t": 255,
"min int8_t": -128,
"max double": 1.79769313486232e+308,
"min double": -1.79769313486232e+308,
"max float": 3.40282346638529e+038,
"zero float": 0.0,
"min float": -3.40282346638529e+038,
"Key too long for small string optimization": "String too long for small string optimization"
}
Example file (store.json):
{ "store": {
"book": [
{ "category": "reference",
"author": "Nigel Rees",
"title": "Sayings of the Century",
"price": 8.95
},
{ "category": "fiction",
"author": "Evelyn Waugh",
"title": "Sword of Honour",
"price": 12.99
},
{ "category": "fiction",
"author": "Herman Melville",
"title": "Moby Dick",
"isbn": "0-553-21311-3",
"price": 8.99
}
]
}
}
#include <jsoncons/json.hpp>
#include <jsoncons_ext/jsonpath/json_query.hpp>
using namespace jsoncons;
using namespace jsoncons::jsonpath;
int main()
{
std::ifstream is("input/booklist.json");
json booklist;
is >> booklist;
// All books whose author's name starts with Evelyn
json result1 = json_query(booklist, "$.store.book[?(@.author =~ /Evelyn.*?/)]");
std::cout << "(1)\n" << pretty_print(result1) << std::endl;
// Change the price of "Moby Dick"
json_replace(booklist,"$.store.book[?(@.isbn == '0-553-21311-3')].price",10.0);
std::cout << "(2)\n" << pretty_print(booklist) << std::endl;
}
Output:
(1)
[
{
"author": "Evelyn Waugh",
"category": "fiction",
"price": 12.99,
"title": "Sword of Honour"
}
]
(2)
{
"store": {
"book": [
{
"author": "Nigel Rees",
"category": "reference",
"price": 8.95,
"title": "Sayings of the Century"
},
{
"author": "Evelyn Waugh",
"category": "fiction",
"price": 12.99,
"title": "Sword of Honour"
},
{
"author": "Herman Melville",
"category": "fiction",
"isbn": "0-553-21311-3",
"price": 10.0,
"title": "Moby Dick"
}
]
}
}
See json_query, json_replace, and Basics for details.
Example file (tasks.csv)
project_id, task_name, task_start, task_finish
4001,task1,01/01/2003,01/31/2003
4001,task2,02/01/2003,02/28/2003
4001,task3,03/01/2003,03/31/2003
4002,task1,04/01/2003,04/30/2003
4002,task2,05/01/2003,
#include <fstream>
#include <jsoncons/json.hpp>
#include <jsoncons_ext/csv/csv_reader.hpp>
#include <jsoncons_ext/csv/csv_serializer.hpp>
using namespace jsoncons;
using namespace jsoncons::csv;
int main()
{
std::ifstream is("input/tasks.csv");
json_decoder<json> decoder;
csv_parameters params;
params.assume_header(true)
.trim(true)
.ignore_empty_values(true)
.column_types({"integer","string","string","string"});
csv_reader reader(is,decoder,params);
reader.read();
ojson tasks = encoder.get_result();
std::cout << "(1)\n" << pretty_print(tasks) << "\n\n";
std::cout << "(2)\n";
csv_serializer serializer(std::cout);
tasks.write(serializer);
}
Output:
(1)
[
{
"project_id": 4001,
"task_name": "task1",
"task_start": "01/01/2003",
"task_finish": "01/31/2003"
},
{
"project_id": 4001,
"task_name": "task2",
"task_start": "02/01/2003",
"task_finish": "02/28/2003"
},
{
"project_id": 4001,
"task_name": "task3",
"task_start": "03/01/2003",
"task_finish": "03/31/2003"
},
{
"project_id": 4002,
"task_name": "task1",
"task_start": "04/01/2003",
"task_finish": "04/30/2003"
},
{
"project_id": 4002,
"task_name": "task2",
"task_start": "05/01/2003"
}
]
(2)
project_id,task_name,task_start,task_finish
4001,task2,02/01/2003,02/28/2003
4001,task3,03/01/2003,03/31/2003
4002,task1,04/01/2003,04/30/2003
4002,task2,05/01/2003,
See csv_reader and csv_serializer for details.
Special thanks to our contributors