Serializing and deserializing JSON with Boost

C++JsonBoostBoost Propertytree

C++ Problem Overview


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.

C++ Solutions


Solution 1 - C++

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

Solution 2 - C++

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.

Solution 3 - C++

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser1049280View Question on Stackoverflow
Solution 1 - C++ArtemGrView Answer on Stackoverflow
Solution 2 - C++Vinnie FalcoView Answer on Stackoverflow
Solution 3 - C++user12271122View Answer on Stackoverflow