blob: fcfe55d7531351ae2cb82718d21e8d53bce1f947 [file] [view] [edit]
<!--
Feature slides for the animated slideshow. build.py adds the title slide before them and the closing slide after them.
# Title one slide per heading; `{badge: TEXT}` at the end adds a red chip
- bullet bullets; a long bullet may continue on indented lines
```cpp ... ``` the code shown on the right (a line starting with `$ ` is a shell command)
-->
# Trivial integration
- single header file
- no build system needed
- vanilla C++11
- works with GCC 4.8+, Clang 3.4+ and MSVC 2015+
```cpp
#include <nlohmann/json.hpp>
// for convenience
using json = nlohmann::json;
int main()
{
// a JSON pretty-printer in 3 lines
json j;
std::cin >> j;
std::cout << std::setw(4) << j << std::endl;
}
$ g++ pretty.cpp -std=c++11 -o pretty
```
# First-class datatype
- write JSON like any other C++ literal
- initializer lists become arrays and objects
```cpp
json j = {
{"pi", 3.141},
{"happy", true},
{"name", "Niels"},
{"nothing", nullptr},
{"answer", {
{"everything", 42}
}},
{"list", {1, 0, 2}},
{"object", {
{"currency", "USD"},
{"value", 42.99}
}}
};
```
# Array construction
- arrays work the way you expect
- adding to a null value makes it an array
```cpp
// create null value
json j;
// add via member function
j.push_back("Hello");
j.emplace_back("World");
// add via += operator
j += false;
// add via index
j[2] = 42.3;
// gaps are filled with null
j[4] = "World";
```
# Object construction
- objects work the way you expect
- adding to a null value makes it an object
```cpp
// create null value
json j;
// add via member function
j.emplace("key2", "value");
j.push_back({"key", "value"});
// add via += operator
j += {"another key", false};
// add via key
j["pi"] = 3.1415926;
j["answer"]["everything"] = 42;
```
# Container operations
- use JSON like an STL container
- satisfies the ReversibleContainer requirements
```cpp
// container empty?
j.empty();
// current number of elements
j.size();
// maximal number of elements
j.max_size();
// swap elements
j.swap(j2);
std::swap(j, j2);
// clear a container
j.clear();
```
# STL containers
- switch between STL and JSON containers
- conversion works in both directions
```cpp
// some STL containers
std::vector<int> v;
std::unordered_map<std::string, bool> m;
// automatic transformation
json j_array(v);
json j_object(m);
// works both ways
auto l = j_array.get<std::list<int>>();
auto u = j_object
.get<std::map<std::string, bool>>();
```
# Type conversion
- convert your own types to and from JSON
- one macro writes to_json and from_json
- or write both functions for full control
```cpp
// some user-defined type
struct person {
std::string name;
int age;
};
// defines to_json and from_json
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(person,
name, age)
// conversion in action
person p {"Ned Flanders", 60};
json j = p;
// {"age": 60, "name": "Ned Flanders"}
auto p2 = j.get<person>();
```
# Type deduction
- types are deduced automatically
- member functions tell you the type
```cpp
// type deduction
json j1 = nullptr;
json j2 = false;
json j3 = 12.23;
json j4 = {1, 2, 3};
json j5 = {{"key", "value"}};
json j6 = "Hello";
// quick checks
j1.is_null();
j2.is_boolean();
j3.is_number();
j4.is_array();
j5.is_object();
j6.is_string();
```
# Serialization
- to a string or a stream
- pretty-printing included
```cpp
// default serialization
auto s1 = j.dump();
// pretty-printed
int indent = 4;
std::string s2 = j.dump(indent);
// to stream
std::cout << j << std::endl;
// pretty-printed
std::cout << std::setw(indent) << j << std::endl;
```
# Deserialization
- parse strings, streams and files
- the _json literal puts plain JSON in your code
- comments and trailing commas on request
```cpp
// from string
json j1 = json::parse("[1,null,false]");
// from file
std::ifstream f("example.json");
json j2 = json::parse(f);
// from string literal
json j3 = "[3.14159]"_json;
// from raw string literal
json j4 = R"(
{"one": 1, "two": 2, "three": [1, 2, 3]}
)"_json;
```
# SAX parsing
- the parser can emit SAX events
- process input without building a JSON value
```cpp
// define a SAX event processor
struct sax_processor : json::json_sax_t
{
bool boolean(bool val) override
{
return true;
}
// implement other functions...
};
// create object
sax_processor my_processor;
// use it to process input
json::sax_parse(input, &my_processor);
```
# Zero-copy views {badge: NEW IN 3.13}
- parse without building a tree: 16 bytes per value
- strings and numbers stay in the source text
- materialize a json value only where you need one
```cpp
#include <nlohmann/json_view.hpp>
// parse into a flat index, not a tree
std::ifstream f("big.json");
auto doc = nlohmann::json_document::parse(f);
// read-only views with familiar access
auto view = doc.root();
double pi = view["pi"].get<double>();
for (auto v : view["list"])
std::cout << v.get<int>() << '\n';
// build a json value only where needed
json part = view["list"].materialize();
```
# JSON Pointer
- address any element with a JSON Pointer
- flatten a value to pointer/value pairs, and back
```cpp
json j = {"good", "bad", "ugly"};
// JSON pointer to the 3rd list element
auto ptr = json::json_pointer("/2");
// use JSON pointer to access element
j[ptr] = {{"it", "cattivo"}};
// user-defined string literal
j["/2/en"_json_pointer] = "ugly";
// ["good","bad",{"en":"ugly","it":"cattivo"}]
json flat = j.flatten();
// {"/0":"good","/1":"bad","/2/en":"ugly",
// "/2/it":"cattivo"}
json j2 = flat.unflatten(); // j == j2
```
# JSON Patches
- use JSON Patch to describe edit operations
- create diffs from two JSON values
- or use a JSON Merge Patch that looks like the document
```cpp
json source = R"({"F": "Paris", "D": "Berlin"})"_json;
// a JSON Patch (RFC 6902)
json p1 = R"([
{"op": "add", "path": "/GB", "value": "London"}
])"_json;
json target = source.patch(p1);
// create a diff from two JSON values
json p2 = json::diff(target, source);
// [{"op": "remove", "path": "/GB"}]
// a JSON Merge Patch (RFC 7396)
target.merge_patch(R"({"F": null})"_json);
// {"D": "Berlin", "GB": "London"}
```
# Binary formats
- compact binary representations
- BJData, BON8, BSON, CBOR, MessagePack and UBJSON
```cpp
// a JSON value
json j = R"({"compact": true, "schema": 0})"_json;
// serialize to CBOR
std::vector<std::uint8_t> v = json::to_cbor(j);
// 0xA2, 0x67, 0x63, 0x6F, 0x6D, 0x70, 0x61,
// 0x63, 0x74, 0xF5, 0x66, 0x73, 0x63, 0x68,
// 0x65, 0x6D, 0x61, 0x00
// roundtrip
json j_from_cbor = json::from_cbor(v);
// the same for the other formats
auto b = json::to_bon8(j);
auto m = json::to_msgpack(j);
```
# Algorithms
- the standard algorithms just work
- sort, find, count, merge and more
```cpp
// sort JSON containers
std::sort(j.begin(), j.end());
// find element
auto pos = std::find(j.begin(), j.end(),
json("needle"));
// count all numbers
auto n = std::count_if(j.begin(), j.end(),
[](const json& v) { return v.is_number(); });
// merge two sorted containers
std::merge(j1.begin(), j1.end(),
j2.begin(), j2.end(),
std::back_inserter(j3));
```
# Iterators
- iterators, const iterators, and reverse iterators
- random access for arrays
- items() gives you keys and values
```cpp
json j = {1, 2, 3, 4, 5};
// range for
for (auto& el : j)
{
// print all values
std::cerr << el << '\n';
}
// classical iterators
for (auto it = j.begin(); it != j.end(); ++it)
{
// double all values
*it = it->get<int>() * 2;
}
```
# Structured bindings
- since C++17, unpack keys and values with structured bindings
```cpp
// JSON object
auto j = R"({"foo": 23, "bar": 42})"_json;
// structured bindings
for (auto& [key, val] : j.items())
{
std::cerr << key << ':' << val << '\n';
}
```