Serializing and deserializing JSON with Boost
Note that property_tree
interprets the keys as paths, e.g. putting the pair "a.b"="z" will create an {"a":{"b":"z"}} JSON, not an {"a.b":"z"}. Otherwise, using property_tree
is trivial. Here is a little example.
#include <sstream>#include <map>#include <boost/property_tree/ptree.hpp>#include <boost/property_tree/json_parser.hpp>using boost::property_tree::ptree;using boost::property_tree::read_json;using boost::property_tree::write_json;void example() { // Write json. ptree pt; pt.put ("foo", "bar"); std::ostringstream buf; write_json (buf, pt, false); std::string json = buf.str(); // {"foo":"bar"} // Read json. ptree pt2; std::istringstream is (json); read_json (is, pt2); std::string foo = pt2.get<std::string> ("foo");}std::string map2json (const std::map<std::string, std::string>& map) { ptree pt; for (auto& entry: map) pt.put (entry.first, entry.second); std::ostringstream buf; write_json (buf, pt, false); return buf.str();}
Boost versions 1.75 and later now have a robust native JSON library:
https://www.boost.org/doc/libs/develop/libs/json/doc/html/index.html
I don't suggest using Boost.PropertyTree's JSON algorithms anymore, as they are not fully compliant with the spec.
Some company asked me to implement JSON serialization library which is faster than boost lib. I did that - it is ~10x times faster then boost lib. I publish the code for anyone touse.
#pragma once#include <string>#include <vector>#include <regex>#include <fstream>enum class JsonNodeType { Array, Object, String };class JsonNode{ JsonNodeType m_nodeType; std::vector<JsonNode*>* m_values{0}; std::vector<std::string>* m_keys{0}; std::string m_value{}; inline static int m_indent; inline static bool m_formatOutput; const int m_indentInc{4};public: JsonNode(JsonNodeType type) { m_nodeType = type; switch (m_nodeType) { case JsonNodeType::Object: m_keys = new std::vector<std::string>(); [[fallthrough]]; case JsonNodeType::Array: m_values = new std::vector<JsonNode*>(); } }; JsonNode(std::string value) { m_nodeType = JsonNodeType::String; m_value = value; } ~JsonNode() { if (m_values) for (JsonNode* node : *m_values) delete node; delete m_values; delete m_keys; } void Add(JsonNode* node) { assert(m_nodeType == JsonNodeType::Array); m_values->push_back(node); } void Add(const char* key, JsonNode* node) { assert(m_nodeType == JsonNodeType::Object); m_values->push_back(node); m_keys->push_back(key); } void Add(const char* key, std::string value) { assert(m_nodeType == JsonNodeType::Object); m_keys->push_back(key); m_values->push_back(new JsonNode(value)); } void Add(std::string value) { assert(m_nodeType == JsonNodeType::Array); m_values->push_back(new JsonNode(value)); } void Add(int value) { assert(m_nodeType == JsonNodeType::Array); m_values->push_back(new JsonNode(std::to_string(value))); } void Add(const char* key, bool value) { assert(m_nodeType == JsonNodeType::Object); m_keys->push_back(key); m_values->push_back(new JsonNode(value ? "true" : "false")); } void OutputToStream(std::ostream& ofs, bool formatOutput = true) { m_indent = 0; m_formatOutput = formatOutput; OutputNodeToStream(ofs); ofs << std::endl; } std::string EscapeString(std::string& str) { std::regex html2json("\\\\|\\/|\\\""); std::regex newline("\n"); std::string tmp = std::regex_replace(str, html2json, "\\$&"); return std::regex_replace(tmp, newline, "\\n"); }private: void OutputNodeToStream(std::ostream& ofs) { switch (m_nodeType) { case JsonNodeType::String: ofs << "\"" << m_value << "\""; break; case JsonNodeType::Object: OutputObjectToStream(ofs); break; case JsonNodeType::Array: OutputArrayToStream(ofs); break; } } void ChangeIndent(std::ostream& ofs, int indentDelta) { if (!m_formatOutput) return; m_indent += indentDelta; ofs << std::endl; } void OutputIndents(std::ostream& ofs) { if (!m_formatOutput) return; for (int i = 0; i < m_indent; i++) ofs << " "; } void OutputObjectToStream(std::ostream& ofs) { assert(m_nodeType == JsonNodeType::Object); assert(m_keys->size() == m_values->size()); if (m_keys->empty()) { ofs << "\"\""; return; } ofs << "{"; ChangeIndent(ofs, m_indentInc); for (int i = 0; i < m_keys->size(); i++) { if (i > 0) ofs << ","; if (i > 0 && m_formatOutput) ofs << std::endl; OutputIndents(ofs); ofs << "\"" << m_keys->at(i) << "\": "; m_values->at(i)->OutputNodeToStream(ofs); } ChangeIndent(ofs, -m_indentInc); OutputIndents(ofs); ofs << "}"; } void OutputArrayToStream(std::ostream& ofs) { assert(m_nodeType == JsonNodeType::Array); if (m_values->empty()) { ofs << "\"\""; return; } ofs << "["; ChangeIndent(ofs, m_indentInc); for (int i = 0; i < m_values->size(); i++) { if (i > 0) ofs << ","; if(i > 0 && m_formatOutput) ofs << std::endl; OutputIndents(ofs); m_values->at(i)->OutputNodeToStream(ofs); } ChangeIndent(ofs, -m_indentInc); OutputIndents(ofs); ofs << "]"; }};
Usage examples
Create json tree:
JsonNode* Circuit::GetMyJson(){ JsonNode* node = new JsonNode(JsonNodeType::Object); JsonNode* gates = new JsonNode(JsonNodeType::Array); for (auto& [k, v] : m_gates) gates->Add(v.GetMyJson()); node->Add("gates", gates); return node;}
Output tree:
std::unique_ptr<JsonNode> node (simulation->GetMyJson());std::ofstream output("output.json", std::ios::out);node->OutputToStream(output);