29

I have a file like this:

[data.json]

{
    "electron": {
        "pos": [0,0,0],
        "vel": [0,0,0]
    },

    "proton": {
        "pos": [1,0,0],
        "vel": [0,0.1,0]
    },

     "proton": {
        "pos": [-1,0,0],
        "vel": [0,-0.1,-0.1]
    }
}

How do I create a vector of particles from parsing this file. As I understand it I need to read the file using boost and read the strings (lines) into a vector, and then parse the contents of the vector.

The class particle is something like this:

class Particle
{

    private:
    particle_type mtype; // particle_type is an enum
    vector<double> mPos;
    vector<double> mVel;
};

Other methods for get/set have been omitted in the class.

Basically I would like help creating a vector<Particle> with the correct position and velocity data and particle_type data parsed into it. Thanks in advance.

Code in main:

int main(){

    boost::property_tree::ptree pt;
    boost::property_tree::read_json("data.json", pt);
}
FreelanceConsultant
  • 13,167
  • 27
  • 115
  • 225

3 Answers3

29

I modified your JSON a bit. Slightly untested code.

{
    "particles": [
        {
            "electron": {
                "pos": [
                    0,
                    0,
                    0
                ],
                "vel": [
                    0,
                    0,
                    0
                ]
            },
            "proton": {
                "pos": [
                    -1,
                    0,
                    0
                ],
                "vel": [
                    0,
                    -0.1,
                    -0.1
                ]
            }
        }
    ]
}

...

#ifdef _MSC_VER
#include <boost/config/compiler/visualc.hpp>
#endif
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/foreach.hpp>
#include <cassert>
#include <exception>
#include <iostream>
#include <sstream>
#include <string>

int main()
{
    try
    {
        std::stringstream ss;
        // send your JSON above to the parser below, but populate ss first


        boost::property_tree::ptree pt;
        boost::property_tree::read_json(ss, pt);

        BOOST_FOREACH(boost::property_tree::ptree::value_type &v, pt.get_child("particles.electron"))
        {
            assert(v.first.empty()); // array elements have no names
            std::cout << v.second.data() << std::endl;
            // etc
        }
        return EXIT_SUCCESS;
    }
    catch (std::exception const& e)
    {
        std::cerr << e.what() << std::endl;
    }
    return EXIT_FAILURE;
}

Modify as you see fit.

Print the entire tree to see what is being read. This helps in debugging.

void print(boost::property_tree::ptree const& pt)
{
    using boost::property_tree::ptree;
    ptree::const_iterator end = pt.end();
    for (ptree::const_iterator it = pt.begin(); it != end; ++it) {
        std::cout << it->first << ": " << it->second.get_value<std::string>() << std::endl;
        print(it->second);
    }
}
  • I did not find this helpful - `No such node (particles.electron)`. For anyone who is not familiar, `std::stringstream ss` should be removed, and `boost::property_tree::read_json(ss, pt);` replaced with `boost::property_tree::read_json(, pt);` – FreelanceConsultant Mar 04 '13 at 21:58
  • @EdwardBird: `read_json` takes a stream, its in boost's documentation. You must not have populated it correctly. –  Mar 04 '13 at 22:21
  • what do you suggest. (See my edit in main) EDIT: There is nothing for me to add in main... What do you suggest? – FreelanceConsultant Mar 04 '13 at 22:22
  • When I print the tree everything looks fine. – FreelanceConsultant Mar 04 '13 at 22:24
  • I think I dont understand why I need a stringstream, or how to open the file into the stringstream, could you help me with that? – FreelanceConsultant Mar 04 '13 at 22:30
  • You don't need a stringstream per se, you just a need a stream. My code was an example. If you can get it to work using a `fstream`, then that's just as well. Use the `<<` operator in conjunction with `ifstream` if you want to populate the `stringstream` from a file. You can also just populate the `stringstream` in code to test a hard-coded JSON if you wish. –  Mar 04 '13 at 22:50
  • I'm still getting the error; no such node. Could you finish the example above or test it? – FreelanceConsultant Mar 04 '13 at 22:54
  • 2
    This example was helpful, but is wrong, it really is worth getting examples to work before posting them IMHO. – SColvin Jan 06 '14 at 16:58
  • I just use the code to read the file, and fill the stringstream. `ss << std::ifstream("data.json", std::ios::binary).rdbuf();`, the data.json contains the json content, but the problem is, I still the the error `No such node (particles.electron)`, I can show the tree by calling `print(pt);`. Any ideas? – ollydbg23 Oct 27 '15 at 08:34
  • Great example just make the following changes:
    After the ss decleration `ss << "{ \"particles\": [ { \"electron\": { \"pos\": [ 0, 0, 0 ], \"vel\": [ 0, 0, 0 ] }, \"proton\": { \"pos\": [ -1, 0, 0 ], \"vel\": [ 0, -0.1, -0.1 ] } } ]}";` Replace the old BOOST_FOREACH loop with `BOOST_FOREACH(boost::property_tree::ptree::value_type &v, pt.get_child("particles")) { assert(v.first.empty()); // array elements have no names print(v.second); // etc }`
    – Jim Mar 21 '17 at 21:23
9

You can iterate with the following code :

boost::property_tree::basic_ptree<std::string,std::string>::const_iterator iter = pt.begin(),iterEnd = pt.end();
for(;iter != iterEnd;++iter)
{
     iter->first; // Your key, at this level it will be "electron", "proton", "proton"
     iter->second; // The object at each step {"pos": [0,0,0], "vel": [0,0,0]}, etc.
}

Hope it helps

Y__
  • 1,687
  • 2
  • 11
  • 23
  • Iter has a first and a second... But what are they? Is there a third as well? – FreelanceConsultant Mar 04 '13 at 17:06
  • 1
    @EdwardBird: `iter` is a pair, so there is no third. `v.first` is an `std::string` holding the parent node and `v.second` is a `boost::property_tree::ptree`, which can be used to parse the fields of the object. You may have to recursively traverse the tree to get all the values depending on how deep your values are buried. –  Mar 04 '13 at 17:18
6

Just correcting issues with the answer above but I couldnt get the formating correct in the comments:

#ifdef _MSC_VER
#include <boost/config/compiler/visualc.hpp>
#endif
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/foreach.hpp>
#include <cassert>
#include <exception>
#include <iostream>
#include <sstream>
#include <string>

void print(boost::property_tree::ptree const& pt)
{
    using boost::property_tree::ptree;
    ptree::const_iterator end = pt.end();
    for (ptree::const_iterator it = pt.begin(); it != end; ++it) {
        std::cout << it->first << ": " << it->second.get_value<std::string>() << std::endl;
        print(it->second);
    }
}

int main()
{
    try
    {
        std::stringstream ss;
        // send your JSON above to the parser below, but populate ss first

        ss << "{ \"particles\": [ { \"electron\": { \"pos\": [ 0, 0, 0 ], \"vel\": [ 0, 0, 0 ] }, \"proton\": { \"pos\": [ -1, 0, 0 ], \"vel\": [ 0, -0.1, -0.1 ] } } ]}";


        boost::property_tree::ptree pt;
        boost::property_tree::read_json(ss, pt);

        BOOST_FOREACH(boost::property_tree::ptree::value_type &v, pt.get_child("particles"))
        {
            assert(v.first.empty()); // array elements have no names
            print(v.second);
        }
        return EXIT_SUCCESS;
    }
    catch (std::exception const& e)
    {
        std::cerr << e.what() << std::endl;
    }
    return EXIT_FAILURE;
}
Jim
  • 2,034
  • 2
  • 15
  • 29
  • still, the program is not running the error is "‘print’ was not declared in this scope " I tried to change it to printf but it did not work. – Aloy A Sen Dec 05 '17 at 14:00
  • print is defined below the main function using ptree types not print. Perhaps you forgot to copy the entire content above. I don't have a computer to retest with right now. – Jim Dec 05 '17 at 17:30
  • Perhaps print needs to be pasted above main – Jim Dec 05 '17 at 17:31