1

I am using boost-property-tree in a C++ application, where I am trying to read a JSON file users.json and store the data into a vector of object (std::vector<User> users;).

The JSON file looks this this:

{
   "OperatingSystem":"Windows 10",
   "users" :
   [
       {
          "firstName":"John",
          "lastName":"Black"
       },
       {
          "firstName":"Kate",
          "lastName":"Red"
       },
       {
          "firstName":"Robin",
          "lastName":"White"
       }
    ]
}

I have succedded reading the OperatingSystem property with the following line of code:

boost::property_tree::ptree treeRoot;

boost::property_tree::read_json("users.json", treeRoot);

std::string operatingSystem = treeRoot.get<std::string>("OperatingSystem");

std::cout << "OS : " << operatingSystem << std::endl;

and that works fine.

In order to store the users, I have created a User class. You can see the header file User.hpp below:

#ifndef USER_H
#define USER_H

#include <iostream>
#include <string>

class User
{
private:
    // Properties
    std::string firstName;
    std::string lastName;

public:
    // Constructors
    User();
    User(std::string firstName, std::string lastName);

    // Getters
    std::string getFirstName();
    std::string getLastName();

    // Setters
    void getFirstName(std::string firstName);
    void getLastName(std::string lastName);
};

#endif // USER_H

and the User.cpp file here:

#include "User.hpp"
#include <iostream>
#include <string>

// Constructors
User::User()
{
    this->firstName = "";
    this->lastName = "";
}

User::User(std::string firstName,   std::string lastName)
{
    this->firstName = firstName;
    this->lastName = lastName;
}

// Getters
std::string User::getFirstName()
{
    return firstName;
}

std::string User::getLastName()
{
    return lastName;
}

// Setters
void User::getFirstName(std::string firstName)
{
    this->firstName = firstName;
}

void User::getLastName(std::string lastName)
{
    this->lastName = lastName;
}

In my main.cpp I am trying to load the users into a vector as such:

#include <iostream>
#include <string>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include "User.hpp"

int main(int argc, char **argv)
{

    boost::property_tree::ptree treeRoot;

    boost::property_tree::read_json("users.json", treeRoot);

    std::vector<User> users;

    users = treeRoot.get<std::vector<User>>("users");

    return 0;
}

but it does not work.

In case someone knows how to read an array of objects from a JSON file via boost::property_tree::ptree, please let me know.

user4581301
  • 33,082
  • 7
  • 33
  • 54
Origamer7
  • 315
  • 3
  • 17
  • Careful with the tagging. Tagging the wrong language will bring extra eyes to your problem, but they aren't the most interested of eyes and may be displeased that you're wasting their time. – user4581301 Dec 06 '19 at 18:59

1 Answers1

5

In property_tree arrays JSON are mapped into nodes (called just ptree). What is node/ptree ?

node/ptree {
  data                              // has data
  list < pair<key,node> > children  // has children
}

In your input object you have property users with value as the array with 3 elements. These elements are mapped into three nodes with empty string as key.

So we have:

"users" node:
    children {"",nodeA}, {"",nodeB}, {"",nodeC}

nodeA,B,C represents elements of arrays. Each element of array is object with 2 properties. Objects like arrays are also mapped into nodes.

So nodeA looks like:

nodeA:
    children {"firstName",nodeD},{"lastName",nodeE} \\ as children we have 2 properties of object

and finally, nodeD is

nodeD:
    data = John 
    children   emptyList

To get users property call get_child().

To iterate over all children use begin\end methods on ptree returned by get. begin\end returns iterator to pair with first as key, and second as nested ptree instance.

The below code iterates over elements in array:

    boost::property_tree::ptree pt;
    boost::property_tree::read_json("in.json",pt);

    auto it = pt.get_child("users");

    for (auto it2 = it.begin(); it2 != it.end(); ++it2)
    {
        for (auto it3 = it2->second.begin(); it3 != it2->second.end(); ++it3)
        {
            std::cout  << it3->first; // [1]
            std::cout << " : " << it3->second.data() << std::endl;
        }
        // [2]
        std::cout << std::endl;
    }

and prints:

firstName : John
lastName : Black

firstName : Kate
lastName : Red

firstName : Robin
lastName : White

in [1] line you should store firstName/lastName and in [2] line you could create new User instance and push into vector.

rafix07
  • 20,001
  • 3
  • 20
  • 33