本文首發於我的博客https://kezunlin.me/post/f3c3eb8/,歡迎閱讀最新內容!c++
tutorial to use nlohmann json for serializing data with modern cpp
<!--more-->git
#include <nlohmann/json.hpp> // for convenience using json = nlohmann::json;
compile withgithub
-std=c++11
# CMakeLists.txt find_package(nlohmann_json 3.2.0 REQUIRED) ... add_library(foo ...) ... target_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json)
{ "pi": 3.141, "happy": true, "name": "Niels", "nothing": null, "answer": { "everything": 42 }, "list": [1, 0, 2], "object": { "currency": "USD", "value": 42.99 } }
with codejson
// create an empty structure (null) json j; // add a number that is stored as double (note the implicit conversion of j to an object) j["pi"] = 3.141; // add a Boolean that is stored as bool j["happy"] = true; // add a string that is stored as std::string j["name"] = "Niels"; // add another null object by passing nullptr j["nothing"] = nullptr; // add an object inside the object j["answer"]["everything"] = 42; // add an array that is stored as std::vector (using an initializer list) j["list"] = { 1, 0, 2 }; // add another object (using an initializer list of pairs) j["object"] = { {"currency", "USD"}, {"value", 42.99} }; // instead, you could also write (which looks very similar to the JSON above) json j2 = { {"pi", 3.141}, {"happy", true}, {"name", "Niels"}, {"nothing", nullptr}, {"answer", { {"everything", 42} }}, {"list", {1, 0, 2}}, {"object", { {"currency", "USD"}, {"value", 42.99} }} };
// create object from string literal json j = "{ \"happy\": true, \"pi\": 3.141 }"_json; // or even nicer with a raw string literal auto j2 = R"( { "happy": true, "pi": 3.141 } )"_json; // parse explicitly auto j3 = json::parse("{ \"happy\": true, \"pi\": 3.141 }"); // explicit conversion to string std::string s = j.dump(); // {\"happy\":true,\"pi\":3.141} // serialization with pretty printing // pass in the amount of spaces to indent std::cout << j.dump(4) << std::endl; // { // "happy": true, // "pi": 3.141 // }
// read a JSON file std::ifstream i("file.json"); json j; i >> j; // write prettified JSON to another file std::ofstream o("pretty.json"); o << std::setw(4) << j << std::endl;
<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<!-- kzl in-article ad -->
<ins class="adsbygoogle"app
style="display:block; text-align:center;" data-ad-layout="in-article" data-ad-format="fluid" data-ad-client="ca-pub-5653382914441020" data-ad-slot="7925631830"></ins>
<script>less
(adsbygoogle = window.adsbygoogle || []).push({});
</script>async
namespace ns { // a simple struct to model a person struct person { std::string name; std::string address; int age; }; }
ns::person p = {"Ned Flanders", "744 Evergreen Terrace", 60}; // convert to JSON: copy each value into the JSON object json j; j["name"] = p.name; j["address"] = p.address; j["age"] = p.age; // ... // convert from JSON: copy each value from the JSON object ns::person p { j["name"].get<std::string>(), j["address"].get<std::string>(), j["age"].get<int>() };
using nlohmann::json; namespace ns { void to_json(json& j, const person& p) { j = json{{"name", p.name}, {"address", p.address}, {"age", p.age}}; } void from_json(const json& j, person& p) { j.at("name").get_to(p.name); j.at("address").get_to(p.address); j.at("age").get_to(p.age); } } // namespace ns // create a person ns::person p {"Ned Flanders", "744 Evergreen Terrace", 60}; // conversion: person -> json json j = p; std::cout << j << std::endl; // {"address":"744 Evergreen Terrace","age":60,"name":"Ned Flanders"} // conversion: json -> person auto p2 = j.get<ns::person>(); // that's it assert(p == p2);
That's all! When calling the json constructor with your type, your customto_json
method will be automatically called. Likewise, when callingget<your_type>()
orget_to(your_type&)
, thefrom_json
method will be called.
namespace nlohmann { template <typename T> struct adl_serializer { static void to_json(json& j, const T& value) { // calls the "to_json" method in T's namespace } static void from_json(const json& j, T& value) { // same thing, but with the "from_json" method } }; }
struct move_only_type { move_only_type() = delete; move_only_type(int ii): i(ii) {} move_only_type(const move_only_type&) = delete; move_only_type(move_only_type&&) = default; int i; }; namespace nlohmann { template <> struct adl_serializer<move_only_type> { // note: the return type is no longer 'void', and the method only takes // one argument static move_only_type from_json(const json& j) { return {j.get<int>()}; } // Here's the catch! You must provide a to_json method! Otherwise you // will not be able to convert move_only_type to json, since you fully // specialized adl_serializer on that type static void to_json(json& j, move_only_type t) { j = t.i; } }; }
exampleside
#pragma once #include <nlohmann/json.hpp> using json = nlohmann::json; #include "sensor_data.h" #include "rfid_info.h" namespace nlohmann { template <> struct adl_serializer<SensorData> { // note: the return type is no longer 'void', and the method only takes // one argument static SensorData from_json(const json& j) { SensorData sensor_data; sensor_data.sensor_identify = j.at("SensorIdentify").get<string>(); return sensor_data; } // Here's the catch! You must provide a to_json method! Otherwise you // will not be able to convert move_only_type to json, since you fully // specialized adl_serializer on that type static void to_json(json& j, SensorData t) { j = json{ {"SensorIdentify",t.sensor_identify},{"SensorType",t.sensor_type },{"Data",t.data} }; } }; template <> struct adl_serializer<RfidInfo> { // note: the return type is no longer 'void', and the method only takes // one argument static RfidInfo from_json(const json& j) { RfidInfo rfid_info; rfid_info.identify = j.at("Identify").get<string>(); return rfid_info; } // Here's the catch! You must provide a to_json method! Otherwise you // will not be able to convert move_only_type to json, since you fully // specialized adl_serializer on that type static void to_json(json& j, RfidInfo t) { j = json{ { "Identify",t.identify },{ "Position",0 } }; } }; }
// create a JSON value json j = R"({"compact": true, "schema": 0})"_json; // serialize to BSON std::vector<std::uint8_t> v_bson = json::to_bson(j); // 0x1B, 0x00, 0x00, 0x00, 0x08, 0x63, 0x6F, ... // roundtrip json j_from_bson = json::from_bson(v_bson);