PrevUpHomeNext

c++ json: boost::property_tree How 4423


> Start
> boost::property_tree json
> iterate boost::property_tree
> Method .empty
> recursive iterate
> Method: .get_child; .first, .second
> understanding types
> json array
> Modify, add, write json data.
> Method .put_value
> Method .add_child
> Write two or more dimensional array
> Back: Home

c++ boost::property_tree is the best json parser for me to parse json data.

boost::property_tree json

>>>> boost::property_tree:
>>>>>>>> read json from file,
>>>>>>>>>>>> from opening filename,
>>>>>>>>>>>> from std::stringstream

get json value by key.

#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <sstream>
#include <iostream>

namespace ptr = boost::property_tree;

int main()
{
	constexpr std::string_view json_data =
		R"(
			{
				"hello" : "world",
				"OK" : true,
				"good" : 2.5,
				"help" :
				{
					"yes" : "no",
					"num" : "yes"
				}
			}
		)"
	;

	ptr::ptree root;

	// json can be read from both std::fstream or std::stringstream
	std::stringstream io;
	io << json_data;

	// ptr::read_json("data.json", root);
	// ptr::read_json(file, root);	// file is std::ifstream object.
	ptr::read_json(io, root);

	{
		auto hello = root.get<std::string>("hello");
		std::cout << hello << std::endl;
	}

	{
		auto good = root.get<double>("good");	// double: 2.5
		auto good2 = root.get<std::string>("good");	// string: 2.5
		std::cout << good << std::endl;
		std::cout << "=> " << good2 << std::endl;
	}

	{
		auto ok = root.get<bool>("OK");	// boolean value: 1 or true
		auto ok2 = root.get<std::string>("OK");	// string value: true
		std::cout << ok << std::endl;
		std::cout << ok2 << std::endl;
	}
}

iterate boost::property_tree

boost::property_tree:
>>>>>>>> iterate json child data

namespace tree = boost::property_tree;

constexpr std::string_view json_data =
	R"(
		{
			"hello" : "world",
			"OK" : true,
			"good" : 2.5,
			"help" :
			{
				"yes" : "no",
				"num" : "yes"
			}
		}
	)"
;

tree::ptree root;
std::stringstream io;
io << json_data;
tree::read_json(io, root);
const tree::ptree & help = root.get_child("help");
for (const auto & [k, v]: help)
{
	std::cout << k << std::endl;
}

// output:
/*
yes
num
*/

Method .empty

boost::property_tree:
>>>>>>>> processing json data.
>>>> Method: .empty()
>>>>>>>> true: no child
>>>>>>>> false: has child
>>>> If true: std::cout << n.data()
>>>>>>>>

namespace tree = boost::property_tree;

constexpr std::string_view json_data =
	R"(
		{
			"hello" : "world",
			"OK" : true,
			"good" : 2.5,
			"help" :
			{
				"yes" : "no",
				"num" : "yes"
			}
		}
	)"
;
std::cout << std::boolalpha;
tree::ptree root;
std::stringstream io;
io << json_data;
tree::read_json(io, root);

{
	const tree::ptree & hello = root.get_child("hello");
	contract_assert(hello.empty());	// empty: true, no child
	std::cout << hello.data() << std::endl;	// world
	std::cout << root.get<std::string>("hello") << std::endl;	// world
}
{
	const tree::ptree & help = root.get_child("help");
	contract_assert(! help.empty());	// empty: false: has child
	for (const auto & [k, v]: help)
	{
		static_assert(std::same_as<decltype(k), const std::string>);
		static_assert(std::same_as<decltype(v), const tree::ptree>);
		contract_assert(v.empty());	// empty: true: no child
		std::cout << k << " => " << v.data() << std::endl;
	}
}

recursive iterate

boost::property_tree:
>>>>>>>> processing json data.

>>>> Recursive loop:
>>>>>>>> Generalized accessing json data.
>>>>>>>>>>>> by using .empty, range-based for loop.

constexpr std::string_view json_data =
	R"(
		{
			"hello" : "world",
			"OK" : true,
			"list" :
			{
				"Bob" : 100,
				"Tom" : 200
			},
			"good" : 2.5,
			"help" :
			{
				"yes" : "no",
				"num" : "yes",
				"pick" :
				{
					"size" : 25.3,
					"health" : true
				}
			}
		}
	)"
;
std::stringstream io;
io << json_data;
tree::ptree root;
tree::read_json(io, root);

std::function<void(tree::ptree)> read =
	[&] (const tree::ptree & node)
	{
		static std::string indent = "";
		if (node.empty())
		{
			std::cout << node.data() << std::endl;
			return;
		}
		else
		{
			std::cout << std::endl;
			for (const auto & [key, value]: node)
			{
				std::cout << indent << key << " => ";
				std::string old = indent;	// stack "store"
				indent += "\t";	// stack "push"
				read(value);
				indent = old;	// stack "restore" ("pop")
			}
		}
	}
;

read(root);

Method: .get_child; .first, .second

==================================================

boost::property_tree::ptree object
ptree::value_ype object

==================================================

>>>> Summary: ptree and ptree::value_type

>>>> ptree behaves like std::map
>>>> ptree::value_type behaves like std::pair

>>>> Every element of ptree is ptree::value_type

>>>> ptree::value_type first type is the key type, it is std::string
>>>> ptree::value_type second type is the data type,
>>>>>>>> however, the second type is ptree

==================================================

>>>> 1. ptree
>>>> 2. ptree::value_type
>>>> 3. From ptree::value_type:
>>>>>>>> .first ---- get std::string
>>>>>>>> .second ---- get ptree
>>>> 4. From ptree:
>>>>>>>> .get ---- Passing key, return value, such as std::string, bool, double
>>>>>>>> .get_child ---- Passing key, return ptree
>>>> 5. iterate ptree with range-based for: (it defined .begin, .end)
>>>>>>>> accessing each ptree::value_type:
>>>>>>>>>>>>>>>> .first is key, type is std::string
>>>>>>>>>>>>>>>> .second is ptree

constexpr std::string_view json_data =
	R"(
		{
			"hello" : "world",
			"OK" : true,
			"list" :
			{
				"Bob" : 100,
				"Tom" : 200
			},
			"good" : 2.5,
			"help" :
			{
				"yes" : "no",
				"num" : "yes",
				"pick" :
				{
					"size" : 25.3,
					"health" : true
				}
			}
		}
	)"
;

namespace ptr = boost::property_tree;
std::stringstream io;
io << json_data;
ptr::ptree root;
ptr::read_json(io, root);

{
	ptr::ptree nn = root.get_child("hello");
	contract_assert(nn.empty());		// no child
	contract_assert(nn.data() == "world");		// only "world"
}
{
	ptr::ptree nn = root.get_child("list");
	contract_assert(! nn.empty());		// has child
	for (const ptr::ptree::value_type & value: nn)
	{
		std::string key_s = value.first;
		ptr::ptree value_s = value.second;
		contract_assert(value_s.empty());
		std::cout << "=> " << value_s.data() << std::endl;
	}
}

understanding types

==================================================

boost::property_tree::ptree object
ptree::value_ype object

==================================================

>>>> Summary: ptree and ptree::value_type

>>>> ptree behaves like std::map
>>>> ptree::value_type behaves like std::pair

>>>> Every element of ptree is ptree::value_type

>>>> ptree::value_type first type is the key type, it is std::string
>>>> ptree::value_type second type is the data type,
>>>>>>>> however, the second type is ptree

==================================================

>>>> 1. ptree
>>>> 2. ptree::value_type
>>>> 3. From ptree::value_type:
>>>>>>>> .first ---- get std::string
>>>>>>>> .second ---- get ptree
>>>> 4. From ptree:
>>>>>>>> .get ---- Passing key, return value, such as std::string, bool, double
>>>>>>>> .get_child ---- Passing key, return ptree
>>>> 5. iterate ptree with range-based for: (it defined .begin, .end)
>>>>>>>> accessing each ptree::value_type:
>>>>>>>>>>>>>>>> .first is key, type is std::string
>>>>>>>>>>>>>>>> .second is ptree

constexpr std::string_view data =
	R"(
		{
			"hello" : "world",
			"OK" : true,
			"list" :
			{
				"Bob" : 100,
				"Tom" : 200
			},
			"good" : 2.5,
			"help" :
			{
				"yes" : "no",
				"num" : "yes",
				"pick" :
				{
					"size" : 25.3,
					"health" : true
				}
			}
		}
	)"
;

namespace ptr = boost::property_tree;
ptr::ptree root;
std::stringstream io;
io << data;
ptr::read_json(io, root);
{
	std::cout << root.get<double>("good") << std::endl;	// 2.5
}
{
	ptr::ptree::value_type data = *root.begin();
	std::string key = data.first;
	ptr::ptree data__ = data.second;
	std::string data_abc = data__.data();
	std::cout << key << " " << data_abc << std::endl;	// hello world
}
{
	for (const ptr::ptree::value_type & pair: root)
	{
		{
			const std::string & key = pair.first;
			const ptr::ptree & data = pair.second;
			if (data.empty())	// empty true: no child
				std::cout << key << " -> " << data.data() << std::endl;
		}
		{
			const auto [key, data] = pair;
			if (data.empty())	// empty tree: no child
				std::cout << key << " => " << data.data() << std::endl;
		}
	}
}
{
	const ptr::ptree & ttt = root.get_child("OK");
	if (ttt.empty())
	{
		const std::string & data = ttt.data();
		std::cout << "=> " << data << std::endl;
	}
}

json array

For json array, get a pair object from ptree object, pair type is ptree::value_type;
>>>>>>>> the first type is the key type, which is an empty std::string.
>>>>>>>> the second type is the value type, which is a ptree.

constexpr std::string_view data =
	R"(
		{
			"version" : 3.0,
			"list" : ["ab", "cd", "ef"],
			"abt" :
			{
				"" : "hot",
				"" : "cold",
				"" : "cool"
			}
		}
	)"
;

namespace ptr = boost::property_tree;
ptr::ptree root;
std::stringstream io;
io << data;
ptr::read_json(io, root);
{
	const ptr::ptree & data = root.get_child("list");
	for (const ptr::ptree::value_type & vt: data)
	{
		contract_assert(vt.first.empty());	// vt.first is std::string
		std::cout << std::quoted(vt.first) << " => "
			<< std::quoted(vt.second.data()) << std::endl;
	}
}
{
	const ptr::ptree & data = root.get_child("abt");
	for (const ptr::ptree::value_type & vt: data)
	{
		contract_assert(vt.first.empty());	// vt.first is std::string
		std::cout << std::quoted(vt.first) << " -> "
			<< std::quoted(vt.second.data()) << std::endl;
	}
}
//output:
/*
"" => "ab"
"" => "cd"
"" => "ef"
"" => "hot"
"" => "cold"
"" => "cool"
*/

Modify, add, write json data.

boost::property_tree::ptree
As ptree is just a map-like container,
>>>>>>>> and ptree::value_type is just a std::pair,
to modify, add, write json data, just access them as
oridinary std:map/std::pair ways.

Method: .push_back
Method: .put : override existed value if its key exists.
Method: .add : always add new key-value.

>>>>>>>> .put and .add ared used for value which is std::string, int, double etc.
>>>>>>>> .push_back is used for value which is a ptree.

namespace ppt = boost::property_tree;
constexpr std::string_view data{R"({"version":"1.0", "age" : 3})"};
ppt::ptree root;
std::stringstream io;
io << data;
ppt::read_json(io, root);

{
	ppt::ptree nn;
	nn.push_back(ppt::ptree::value_type{"eggs", ppt::ptree{"two"}});
	nn.push_back(ppt::ptree::value_type{"hot", "yes"});
	root.push_back(ppt::ptree::value_type{"world", nn});
	root.push_back(ppt::ptree::value_type{"star", nn});
}
{
	root.put("version", "3.0");	// Override existed "1.0" to "3.0"
	root.put("age", 5);	// Override existed 3 to 5
	root.put("large", "yes");	// Create a new pair: "large" : yes"
	root.add("small", "no");	// Create a new pair: "small", "no"
	root.add("small", "open");	// Create a new pair: "small", "open"
}
{
	std::ofstream out{"./saved.json"};
	ppt::write_json(out, root, true);	// pretty: true, default is tree
}
{
	std::ostringstream out;
	ppt::write_json(out, root, true);
	std::cout << "Well====>\n" << out.str() << std::flush;
}

Method .put_value

>>>> Method .put_value is the method of boost::property_tree::ptree object.
>>>>>>>> It is used for making an unnamed ptree object,
>>>>>>>>>>>> which has a value but does not have a key.

There is method .put_value, but no method .get_value.

namespace ptr = boost::property_tree;
ptr::ptree root;
root.put("Hello", "World");
root.put("size", 100);
{
	{
		ptr::ptree vn;
		vn.put_value(3.5);
		root.push_back(ptr::ptree::value_type{"one", vn});
	}
	{
		ptr::ptree vn;
		vn.put_value("good");
		root.push_back(ptr::ptree::value_type{"info", vn});
	}
}
{
	std::ostringstream out;
	ptr::write_json(out, root, true);
	std::cout << out.str() << std::endl;
}
/*
{
    "Hello": "World",
    "size": "100",
    "one": "3.5",
    "info": "good"
}
*/

Method .add_child

.add_child adds a child with key and a ptree object.

namespace ptr = boost::property_tree;
ptr::ptree root;
root.put("Hello", "World");
root.put("hole", 33.5);
root.add_child("when", ptr::ptree{"now"});
ptr::ptree sub;
sub.put("one", 1);
sub.put("two", 2);
root.add_child("numbers", sub);
{
	std::ostringstream out;
	ptr::write_json(out, root, true);
	std::cout << out.str() << std::flush;
}
/*
{
    "Hello": "World",
    "hole": "33.5",
    "when": "now",
    "numbers": {
        "one": "1",
        "two": "2"
    }
}
*/

Write two or more dimensional array

Mind Map:

>>>> Use method .put_value to create no-key list (like array);
>>>>>>>> and no-key list can be used as a value of no-key for nested.

But whatever, we need a key at last. If no key is explicitly set,
>>>> an empty string key will be selected.

>>>> Method .put_value is used to add a no-key value.
>>>> Method .push_back can be used to add a no-key ptree.
>>>> Method .add_child can not be used to add a no-key ptree.

namespace pt = boost::property_tree;
pt::ptree root;
{
	pt::ptree sub;
	{ // row 1
		pt::ptree row;
		{ // value 1
			pt::ptree item;
			item.put_value("Hello");

			// no-key: empty string key
			row.push_back(pt::ptree::value_type{"", item});

			// Runtime assert error. Method .add_child key can not empty.
			//row.add_child("", item);
		}
		{ // value 2
			pt::ptree item;
			item.put_value(7.225);
			row.push_back(pt::ptree::value_type{"", item});
		}
		sub.push_back(pt::ptree::value_type{"", row});
	}
	{ // row 2
		pt::ptree row;
		{ // value 1
			pt::ptree item;
			item.put_value(1234567);
			row.push_back(pt::ptree::value_type{"", item});
		}
		{ // value 2
			pt::ptree item;
			item.put_value("Hello, c++");
			row.push_back(pt::ptree::value_type{"", item});
		}
		sub.push_back(pt::ptree::value_type{"", row});
	}
	root.add_child("two dimensional array", sub);
}
{ // print
	std::stringstream io;
	pt::write_json(io, root, true);
	std::cout << io.str() << std::flush;
}

//////////////////////////////////////////////////////////////////////

Home

//////////////////////////////////////////////////////////////////////

Sun Jul 12 08:44:37 AM UTC 2026

//////////////////////////////////////////////////////////////////////

Helpful

Spaceship 50 Years Alienated

Role

+

Github:
https://github.com/cppfx/cpphtgt

+

Powered by:
B2 Build | boost quickbook

+

Donate

+

@cppfx.xyz


















PrevUpHomeNext