Search code examples
c++jsonboostboost-propertytree

Getting an exception when reading values using BOOST_FOREACH from the JSON array in C++


I am getting the below error when reading the values using BOOST_FOREACH:

Unhandled exception at 0x76FCB502 in JSONSampleApp.exe: Microsoft C++ exception: boost::wrapexcept<boost::property_tree::ptree_bad_path> at memory location 0x00CFEB18.

Could someone help me how to read values from the array with the below JSON format?

#include <string>
#include <iostream>
#include <boost/property_tree/json_parser.hpp>
#include <boost/foreach.hpp>

using namespace std;

using boost::property_tree::ptree;

int main()
{
const char* f_strSetting = R"({"Class": [{"Student": {"Name":"John","Course":"C++"}}]})";

    boost::property_tree::ptree pt1;
    std::istringstream l_issJson(f_strSetting);
    boost::property_tree::read_json(l_issJson, pt1);

    BOOST_FOREACH(boost::property_tree::ptree::value_type & v, pt1.get_child("Class.Student"))
    {
        std::string l_strName;
        std::string l_strCourse;
        l_strName = v.second.get <std::string>("Name");
        l_strCourse = v.second.get <std::string>("Course");

        cout << l_strName << "\n";
        cout << l_strCourse << "\n";
    }

    return 0;
}

Solution

  • You asked a very similar question yesterday. We told you not to abuse a property tree library to parse JSON. I even anticipated:

    For more serious code you might want to use type-mapping

    Here's how you'd expand from that answer to parse the entire array into a vector at once:

    Live On Coliru

    #include <boost/json.hpp>
    #include <boost/json/src.hpp> // for header-only
    #include <iostream>
    #include <string>
    namespace json = boost::json;
    
    struct Student {
        std::string name, course;
    
        friend Student tag_invoke(json::value_to_tag<Student>, json::value const& v) {
            std::cerr << "DEBUG: " << v << "\n";
            auto const& s = v.at("Student");
            return {
                value_to<std::string>(s.at("Name")),
                value_to<std::string>(s.at("Course")),
            };
        }
    };
    
    using Class = std::vector<Student>;
    
    int main()
    {
        auto doc = json::parse(R"({ "Class": [
                { "Student": { "Name": "John", "Course": "C++" } },
                { "Student": { "Name": "Carla", "Course": "Cobol" } }
            ]
        })");
        auto c = value_to<Class>(doc.at("Class"));
    
        for (Student const& s : c)
            std::cout << "Name: " << s.name << ", Course: " << s.course << "\n";
    }
    

    Printing

    Name: John, Course: C++
    Name: Carla, Course: Cobol
    

    I even threw in a handy debug line in case you need to help figuring out exactly what you get at some point:

    DEBUG: {"Student":{"Name":"John","Course":"C++"}}
    DEBUG: {"Student":{"Name":"Carla","Course":"Cobol"}}