How to use boost::property_tree to load and write JSON

21 Dec 2015

Property Tree is a sublibrary of boost that allow you handling tree of property. It can be used to represent XML, JSON, INI files, file paths, etc. In our case, we will be interested in loading and writing JSON, to provide an interface with other applications.

Reading data

Let’s have a look at how we can load those data into our c++ application.

Setting up

First, we need to include the libraries and load the file.

#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
// Short alias for this namespacenamespacept=boost::property_tree;// Create a rootpt::ptreeroot;// Load the json file in this ptreept::read_json("filename.json",root);

Now, we have a populated property tree thatis waiting from us to look at him. Notice that you can also read from a stream, for example pt::read_json(std::cin, root){.cpp} is also allowed.

If your json file is illformed, you will be granted by a pt::json_parser::json_parser_error.

Loading some values

We can access a value from the root by giving it’s path to the get method.

// Read valuesintheight=root.get<int>("height",0);// You can also go through nested nodesstd::stringmsg=root.get<std::string>("some.complex.path");

If the field your are looking to doesn’t exists, the get() method will throw a pt::ptree_bad_path exception, so that you can recorver from incomplete json files. Notice you can set a default value as second argument, or use get_optional<T>() wich return a boost::optional<T>.

Notice the getter doesn’t care about the type of the input in the json file, but only rely on the ability to convert the string to the type you are asking.

Browsing lists

So now, we would like to read a list of objects (in our cases, a list of animals).

We can handle it with a simple for loop, using an iterator. In c++11, it become :

// A vector to allow storing our animalsstd::vector<std::pair<std::string,std::string>>animals;// Iterator over all animalsfor(pt::ptree::value_type&animal:root.get_child("animals")){// Animal is a std::pair of a string and a child// Get the label of the nodestd::stringname=animal.first;// Get the content of the nodestd::stringcolor=animal.second.data();animals.push_back(std::make_pair(name,color));}

Since animal.second is a ptree, we can also call call get() or get_child() in the case our node wasn’t just a string.

A bit more complexe example is given by a list of values. Each element of the list is actualy a std::pair("", value) (where value is a ptree). It doesnt means that reading it is harder.

Add values

Add a list of objects

No big deel here, although we now use add_child() to put our animal node at the root.

// Create a nodept::ptreeanimals_node;// Add animals as childsfor(auto&animal:animals)animals_node.put(animal.first,animal.second);// Add the new node to the rootroot.add_child("animals",animals_node);

Add many nodes with the same name

Now start the tricky tricks. If you want to add more than one time a node
named fish, you can’t call the put() method. The call node.put("name", value) will
replace the existing node named name. But you can do it by manually pushing your nodes,
as demonstrated bellow.

// Add two objects with the same namept::ptreefish1;fish1.put_value("blue");pt::ptreefish2;fish2.put_value("yellow");oroot.push_back(std::make_pair("fish",fish1));oroot.push_back(std::make_pair("fish",fish2));

Add a list of values

If you remember, list are mades of nodes with empty name. Se we have to build node with empty names, and then use the push_back() once again to add all those unnamed childs.

// Add a listpt::ptreefruits_node;for(auto&fruit:fruits){// Create an unnamed node containing the valuept::ptreefruit_node;fruit_node.put("",fruit);// Add this node to the list.fruits_node.push_back(std::make_pair("",fruit_node));}root.add_child("fruits",fruits_node);

Add a matrix

We already have all the tools needed to export our matrix. But let’s demonstrate how to do it.

// Add a matrixpt::ptreematrix_node;for(inti=0;i<3;i++){pt::ptreerow;for(intj=0;j<3;j++){// Create an unnamed valuept::ptreecell;cell.put_value(matrix[i][j]);// Add the value to our rowrow.push_back(std::make_pair("",cell));}// Add the row to our matrixmatrix_node.push_back(std::make_pair("",row));}// Add the node to the rootroot.add_child("matrix",matrix_node);

References

You can download a C++ example and the input JSON file for experimenting. Compile it with clang++ -std=c++11 example.cpp -o example.