I'm newbie to C++. What's the easiest way to serialize and deserialize data of type std::Map
using boost
. I've found some examples with using PropertyTree
but they are obscure for me.
71
votes
3 Answers
96
votes
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();
}
2
votes
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.
-1
votes
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 to use.
#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);