Skip to content

A modern C++, header-only library for constructing JSON and JSON-like text and binary data formats, with JSON Pointer, JSON Patch, JsonPath, CSV, MessagePack, CBOR

License

Notifications You must be signed in to change notification settings

Anodl/jsoncons

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

jsoncons is a C++, header-only library for constructing JSON and JSON-like data formats (e.g. CBOR). It supports

  • Parsing JSON-like text or binary data into an unpacked representation that defines an interface for accessing and modifying that data.

  • Serializing the unpacked representation into different JSON-like text or binary data.

  • Converting from JSON-like text or binary data to C++ objects and back.

  • Streaming JSON read and write events, somewhat analogously to SAX processing in the XML world.

It is distributed under the Boost Software License.

jsoncons uses some features that are new to C++ 11, including move semantics and the AllocatorAwareContainer concept. It has been tested with 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.

Benchmarks

json_benchmarks provides some measurements about how jsoncons compares to other json libraries.

Get jsoncons

Download the latest release and unpack the zip file. Copy the directory include/jsoncons to your include directory. If you wish to use extensions, copy include/jsoncons_ext as well.

Or, download the latest code on master.

How to use it

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.

What's new on master

  • The CSV extension now supports multi-valued fields separated by subfield delimiters

  • New functions decode_json and encode_json convert JSON formatted strings to C++ objects and back. These functions attempts to perform the conversion by streaming using json_convert_traits, and if streaming is not supported, fall back to using json_type_traits. decode_json and encode_json will work for all types that have json_type_traits defined.

Extensions

Planned new features are listed on the roadmap

A simple program using jsoncons

#include <iostream>
#include <fstream>
#include <jsoncons/json.hpp>

// For convenience
using jsoncons::json;

int main()
{
    json color_spaces = json::array();
    color_spaces.push_back("sRGB");
    color_spaces.push_back("AdobeRGB");
    color_spaces.push_back("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 export_settings;

    // create "File Format Options" as an object and put "Color Spaces" in it
    export_settings["File Format Options"]["Color Spaces"] = std::move(color_spaces); 

    export_settings["Image Sizing"] = std::move(image_sizing);

    // Write to stream
    std::ofstream os("export_settings.json");
    os << export_settings;

    // Read from stream
    std::ifstream is("export_settings.json");
    json j = json::parse(is);

    // Pretty print
    std::cout << "(1)\n" << pretty_print(j) << "\n\n";

    // Get reference to object member
    const json& val = j["Image Sizing"];

    // Access member as double
    std::cout << "(2) " << "Dimension 1 = " << val["Dimension 1"].as<double>() << "\n\n";

    // Try access member with default
    std::cout << "(3) " << "Dimension 2 = " << val.get_with_default("Dimension 2",0.0) << "\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 = 0.0

About jsoncons::basic_json

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. A basic_json provides an unpacked representation of JSON-like string or binary data formats, and defines an interface for accessing and modifying that data.

typedef basic_json<char,
                   ImplementationPolicy = sorted_policy,
                   Allocator = std::allocator<char>> json;

The library includes four instantiations of basic_json:

  • json constructs a utf8 character json value that sorts name-value members alphabetically

  • ojson constructs a utf8 character json value that preserves the original name-value insertion order

  • wjson constructs a wide character json value that sorts name-value members alphabetically

  • wojson constructs a wide character json value that preserves the original name-value insertion order

Features

By default, accepts and ignores C-style comments

    std::string s = R"(
    {
        // Single line comments
        /*
            Multi line comments 
        */
    }
    )";

    // Default
    json j = json::parse(s);
    std::cout << "(1) " << j << std::endl;

    // Strict
    try
    {
        strict_parse_error_handler err_handler;
        json j = json::parse(s, err_handler);
    }
    catch (const parse_error& e)
    {
        std::cout << "(2) " << e.what() << std::endl;
    }

Output:

(1) {}
(2) Illegal comment at line 3 and column 10

Validation without parse exceptions

    std::string s = R"(
    {
        "StartDate" : "2017-03-01",
        "MaturityDate" "2020-12-30"          
    }
    )";
    std::stringstream is(s);

    json_reader reader(is);

    std::error_code ec;
    reader.read(ec);
    if (ec)
    {
        std::cout << ec.message() 
                  << " on line " << reader.line_number()
                  << " and column " << reader.column_number()
                  << std::endl;
    }

Output:

Expected name separator ':' on line 4 and column 20

Range-based for loops with arrays

    json book = json::array{1,2,3,4};

    for (auto val : book.array_range())
    {
        std::cout << val << std::endl;
    }

Range-based for loops with objects

    json book = json::object{
        {"author", "Haruki Murakami"},
        {"title", "Kafka on the Shore"},
        {"price", 25.17}
    };

    for (const auto& kv : book.object_range())
    {
        std::cout << kv.key() << "=" 
                  << kv.value() << std::endl;
    }

_json and _ojson literal operators

    using namespace jsoncons::literals;


    ojson j2 = R"(
    {
        "StartDate" : "2017-03-01",
        "MaturityDate" : "2020-12-30"          
    }
    )"_ojson;

Multi-dimensional json arrays

    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 json::make_array for details

Merge key-value pairs from another json object

    json j = json::parse(R"(
    {
        "a" : "1",
        "b" : [1,2,3]
    }
    )");

    json source = json::parse(R"(
    {
        "a" : "2",
        "c" : [4,5,6]
    }
    )");

    j.merge(std::move(source));
    std::cout << pretty_print(j) << std::endl;

Output:

{
    "a": "1",
    "b": [1,2,3],
    "c": [4,5,6]
}

See json::merge and json::merge_or_update for details.

Convert unpacked json values to standard library types and back

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>>();

std::map<std::string,int> m{{"one",1},{"two",2},{"three",3}};
json j(m);
std::cout << "(2) " << j << std::endl;
std::unordered_map<std::string,int> um = j.as<std::unordered_map<std::string,int>>();

Output:

(1) [1,2,3,4]

(2) {"one":1,"three":3,"two":2}

See json_type_traits

Convert unpacked json values to user defined types and back (also standard library containers of user defined types)

    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.

Convert JSON formatted text to C++ objects, and back

The functions decode_json and encode_json convert JSON formatted strings to C++ objects and back. These functions attempt to perform the conversion by streaming json read and write events with the help of 'json_convert_traits', and if that is not supported, fall back to using json_type_traits. decode_json and encode_json will work for all types that have json_type_traits defined.

#include <iostream>
#include <map>
#include <tuple>
#include <jsoncons/json.hpp>

using namespace jsoncons;

int main()
{
    typedef std::map<std::string,std::tuple<std::string,std::string,double>> employee_collection;

    employee_collection employees = 
    { 
        {"John Smith",{"Hourly","Software Engineer",10000}},
        {"Jane Doe",{"Commission","Sales",20000}}
    };

    std::string s;
    jsoncons::encode_json(employees, s, jsoncons::indenting::indent);
    std::cout << "(1)\n" << s << std::endl;
    auto employees2 = jsoncons::decode_json<employee_collection>(s);

    std::cout << "\n(2)\n";
    for (const auto& pair : employees2)
    {
        std::cout << pair.first << ": " << std::get<1>(pair.second) << std::endl;
    }
}

Output:

(1)
{
    "Jane Doe": ["Commission","Sales",20000.0],
    "John Smith": ["Hourly","Software Engineer",10000.0]
}

(2)
Jane Doe: Sales
John Smith: Software Engineer

decode_json and encode_json are supported for many standard library types, and for
user defined types

See decode_json and encode_json

Dump json fragments into a larger document

#include <jsoncons/json.hpp>

using namespace jsoncons;

int main()
{
    const json some_books = json::parse(R"(
    [
        {
            "title" : "Kafka on the Shore",
            "author" : "Haruki Murakami",
            "price" : 25.17
        },
        {
            "title" : "Women: A Novel",
            "author" : "Charles Bukowski",
            "price" : 12.00
        }
    ]
    )");

    const json more_books = json::parse(R"(
    [
        {
            "title" : "A Wild Sheep Chase: A Novel",
            "author" : "Haruki Murakami",
            "price" : 9.01
        },
        {
            "title" : "Cutter's Way",
            "author" : "Ivan Passer",
            "price" : 8.00
        }
    ]
    )");

    json_serializer serializer(std::cout, jsoncons::indenting::indent); // pretty print
    serializer.begin_json();
    serializer.begin_array();
    for (const auto& book : some_books.array_range())
    {
        book.dump_fragment(serializer);
    }
    for (const auto& book : more_books.array_range())
    {
        book.dump_fragment(serializer);
    }
    serializer.end_array();
    serializer.end_json();
}

Output:

[
    {
        "author": "Haruki Murakami",
        "price": 25.17,
        "title": "Kafka on the Shore"
    },
    {
        "author": "Charles Bukowski",
        "price": 12.0,
        "title": "Women: A Novel"
    },
    {
        "author": "Haruki Murakami",
        "price": 9.01,
        "title": "A Wild Sheep Chase: A Novel"
    },
    {
        "author": "Ivan Passer",
        "price": 8.0,
        "title": "Cutter's Way"
    }
]

Filter json names and values

You can rename object members with the built in filter rename_object_member_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_object_member_filter filter2("fifth", "fourth", serializer);
    rename_object_member_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.dump(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.

Extensions

jsonpointer

Example. Select author from second book

#include <jsoncons/json.hpp>
#include <jsoncons_ext/jsonpointer/jsonpointer.hpp>

using namespace jsoncons;

int main()
{
    json doc = json::parse(R"(
    [
      { "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
      }
    ]
    )");

    // Using exceptions to report errors
    try
    {
        json result = jsonpointer::get(doc, "/1/author");
        std::cout << "(1) " << result << std::endl;
    }
    catch (const jsonpointer::jsonpointer_error& e)
    {
        std::cout << e.what() << std::endl;
    }

    // Using error codes to report errors
    std::error_code ec;
    json result = jsonpointer::get(doc, "/0/title", ec);

    if (ec)
    {
        std::cout << ec.message() << std::endl;
    }
    else
    {
        std::cout << "(2) " << result << std::endl;
    }
}

Output:

(1) "Evelyn Waugh"
(2) "Sayings of the Century"

jsonpointer::get may also be used to query the nested data items of a packed CBOR value.

See jsonpointer for details.

jsonpatch

#include <jsoncons/json.hpp>
#include <jsoncons_ext/jsonpatch/jsonpatch.hpp>

using namespace jsoncons;
using namespace jsoncons::literals;

int main()
{
    // Apply a JSON Patch

    json doc = R"(
        { "foo": "bar"}
    )"_json;

    json doc2 = doc;

    json patch = R"(
        [
            { "op": "add", "path": "/baz", "value": "qux" },
            { "op": "add", "path": "/foo", "value": [ "bar", "baz" ] }
        ]
    )"_json;

    std::error_code ec;
    jsonpatch::apply_patch(doc, patch, ec);

    std::cout << "(1)\n" << pretty_print(doc) << std::endl;

    // Create a JSON Patch from two JSON documents

    auto patch2 = jsonpatch::from_diff(doc2,doc);

    std::cout << "(2)\n" << pretty_print(patch2) << std::endl;

    jsonpatch::apply_patch(doc2, patch2, ec);

    std::cout << "(3)\n" << pretty_print(doc2) << std::endl;
}

Output:

(1)
{
    "baz": "qux",
    "foo": ["bar","baz"]
}
(2)
[
    {
        "op": "replace",
        "path": "/foo",
        "value": ["bar","baz"]
    },
    {
        "op": "add",
        "path": "/baz",
        "value": "qux"
    }
]
(3)
{
    "baz": "qux",
    "foo": ["bar","baz"]
}

See jsonpatch for details.

jsonpath

Example file (booklist.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;

    // Normalized path expressions
    json result2 = json_query(booklist, "$.store.book[?(@.author =~ /Evelyn.*?/)]", 
                              result_type::path);
    std::cout << "(2)\n" << pretty_print(result2) << std::endl;

    // Change the price of "Moby Dick"
    json_replace(booklist,"$.store.book[?(@.isbn == '0-553-21311-3')].price",10.0);
    std::cout << "(3)\n" << pretty_print(booklist) << std::endl;

}

Output:

(1)
[
    {
        "author": "Evelyn Waugh",
        "category": "fiction",
        "price": 12.99,
        "title": "Sword of Honour"
    }
]
(2)
[
    "$['store']['book'][1]"
]
(3)
{
    "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 jsonpath for details.

cbor

The cbor extension supports decoding a packed CBOR value to an unpacked (json) value and encoding an unpacked (json) value to a packed CBOR value. It also supports a set of operations on a view of a packed CBOR value for iterating over and accessing nested CBOR data items.

This example illustrates encoding a Reputation Interchange data object to and from cbor.

#include <jsoncons/json.hpp>
#include <jsoncons_ext/cbor/cbor.hpp>
#include <jsoncons_ext/jsonpointer/jsonpointer.hpp>

using namespace jsoncons;

int main()
{
    ojson j1 = ojson::parse(R"(
    {
       "application": "hiking",
       "reputons": [
       {
           "rater": "HikingAsylum.example.com",
           "assertion": "is-good",
           "rated": "sk",
           "rating": 0.90
         }
       ]
    }
    )");

    // Encoding an unpacked (json) value to a packed CBOR value
    std::vector<uint8_t> data;
    cbor::encode_cbor(j1, data);

    // Decoding a packed CBOR value to an unpacked (json) value
    ojson j2 = cbor::decode_cbor<ojson>(data);
    std::cout << "(1)\n" << pretty_print(j2) << "\n\n";

    // Iterating over and accessing the nested data items of a packed CBOR value
    cbor::cbor_view datav{data};    
    cbor::cbor_view reputons = datav.at("reputons");    

    std::cout << "(2)\n";
    for (auto element : reputons.array_range())
    {
        std::cout << element.at("rated").as_string() << ", ";
        std::cout << element.at("rating").as_double() << "\n";
    }
    std::cout << std::endl;

    // Querying a packed CBOR value for a nested data item with jsonpointer
    std::error_code ec;
    cbor::cbor_view rated = jsonpointer::get(datav, "/reputons/0/rated", ec);
    if (!ec)
    {
        std::cout << "(3) " << rated.as_string() << "\n";
    }

Output:

(1)
{
    "application": "hiking",
    "reputons": [
        {
            "rater": "HikingAsylum.example.com",
            "assertion": "is-good",
            "rated": "sk",
            "rating": 0.9
        }
    ]
}

(2)
sk, 0.9

(3) sk

See cbor for details.

msgpack

The msgpack extension supports encoding json to and decoding from the MessagePack binary serialization format.

Example file (book.json):

[
    {
        "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
    }
]
#include <jsoncons/json.hpp>
#include <jsoncons_ext/msgpack/msgpack.hpp>

using namespace jsoncons;
using namespace jsoncons::msgpack;

int main()
{
    std::ifstream is("input/book.json");
    ojson j1;
    is >> j1;

    // Encode ojson to MessagePack
    std::vector<uint8_t> v;
    encode_msgpack(j1, v);

    // Decode MessagePack to ojson 
    ojson j2 = decode_msgpack<ojson>(v);

    std::cout << pretty_print(j2) << std::endl;

    // or to json (now alphabetically sorted)
    json j3 = decode_msgpack<json>(v);

    // or to wjson (converts from utf8 to wide characters)
    wjson j4 = decode_msgpack<wjson>(v);
}

Output:

[
    {
        "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
    }
]

See msgpack for details.

csv

Example file (sales.csv)

customer_name,has_coupon,phone_number,zip_code,sales_tax_rate,total_amount
"John Roe",true,0272561313,01001,0.05,431.65
"Jane Doe",false,416-272-2561,55416,0.15,480.70
"Joe Bloggs",false,"4162722561","55416",0.15,300.70
"John Smith",FALSE,NULL,22313-1450,0.15,300.70
#include <fstream>
#include <jsoncons/json.hpp>
#include <jsoncons_ext/csv/csv_reader.hpp>

using namespace jsoncons;
using namespace jsoncons::csv;

int main()
{
    csv_parameters params;
    params.assume_header(true);

    params.mapping(mapping_type::n_objects);
    std::ifstream is1("input/sales.csv");
    ojson j1 = decode_csv<ojson>(is1,params);
    std::cout << "\n(1)\n"<< pretty_print(j1) << "\n";

    params.mapping(mapping_type::n_rows);
    std::ifstream is2("input/sales.csv");
    ojson j2 = decode_csv<ojson>(is2,params);
    std::cout << "\n(2)\n"<< pretty_print(j2) << "\n";

    params.mapping(mapping_type::m_columns);
    std::ifstream is3("input/sales.csv");
    ojson j3 = decode_csv<ojson>(is3,params);
    std::cout << "\n(3)\n"<< pretty_print(j3) << "\n";
}

Output:

(1)
[
    {
        "customer_name": "John Roe",
        "has_coupon": true,
        "phone_number": "0272561313",
        "zip_code": "01001",
        "sales_tax_rate": 0.05,
        "total_amount": 431.65
    },
    {
        "customer_name": "Jane Doe",
        "has_coupon": false,
        "phone_number": "416-272-2561",
        "zip_code": 55416,
        "sales_tax_rate": 0.15,
        "total_amount": 480.7
    },
    {
        "customer_name": "Joe Bloggs",
        "has_coupon": false,
        "phone_number": "4162722561",
        "zip_code": "55416",
        "sales_tax_rate": 0.15,
        "total_amount": 300.7
    },
    {
        "customer_name": "John Smith",
        "has_coupon": false,
        "phone_number": null,
        "zip_code": "22313-1450",
        "sales_tax_rate": 0.15,
        "total_amount": 300.7
    }
]

(2)
[
    ["customer_name","has_coupon","phone_number","zip_code","sales_tax_rate","total_amount"],
    ["John Roe",true,"0272561313","01001",0.05,431.65],
    ["Jane Doe",false,"416-272-2561",55416,0.15,480.7],
    ["Joe Bloggs",false,"4162722561","55416",0.15,300.7],
    ["John Smith",false,null,"22313-1450",0.15,300.7]
]

(3)
{
    "customer_name": ["John Roe","Jane Doe","Joe Bloggs","John Smith"],
    "has_coupon": [true,false,false,false],
    "phone_number": ["0272561313","416-272-2561",4162722561,null],
    "zip_code": ["01001",55416,55416,"22313-1450"],
    "sales_tax_rate": [0.05,0.15,0.15,0.15],
    "total_amount": [431.65,480.7,300.7,300.7]
}

See csv for details.

Building the test suite and examples with CMake

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/tests/build/cmake/README.txt

Instructions for building the examples with CMake may be found in

jsoncons/examples/build/cmake/README.txt

Acknowledgements

Special thanks to our contributors

About

A modern C++, header-only library for constructing JSON and JSON-like text and binary data formats, with JSON Pointer, JSON Patch, JsonPath, CSV, MessagePack, CBOR

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • C++ 99.2%
  • Other 0.8%