Search code examples
c++jsonboostc++14

JSON data processing in c++14 (Boost)


I am new in C++ (I use most of the time embeded c). I have something like this JSON data:

[10, 
"Session" ,
{"currentYear":"2048","accidents":10,"status":"Accepted"}]

I am trying to process this data:

boost::json::value testVal;
boost::json::error_code ec;
testVal = boost::json::parse(data, ec);

So I have multiple items in testVal and I need to get object from testVal to test something like this:

boost::json::object testObj = testVal.get_object();
if(testObj.at("currentYear") == "2048")
{
// Do Something
}

But I am unable to get instance of object, where are the data which I am looking for.

Any idea how to check (using boost::json) if the data in currentYear are 2048?

Thank you for help.


Solution

  • The straightforward would be

    Compiler Explorer

    for (auto& element : testVal.as_array()) {
        if (!element.is_object())
            continue;
        if (element.as_object()["currentYear"].as_string() == "2048") {
            std::cout << element << std::endl;
        }
    }
    

    Though I recommend using the conversion facilities in the library. (Will add sample later)

    value_to

    The magic conversions turn out a little bit contrived since your input is... underspecified. I'm assuming you filter the objects from the array, and let's for fun do case and whitespace insensitive parsing of the Accepted value into some kind of enum:

    Godbolt

    #include <boost/json.hpp>
    #include <boost/json/src.hpp>
    #include <boost/range/adaptors.hpp>
    #include <boost/spirit/home/x3.hpp>
    #include <iostream>
    namespace json = boost::json;
    using boost::adaptors::filtered;
    
    struct Insurance {
        long   currentYear, accidents;
        enum class Status { Accepted, Rejected, Pending } status;
    
        friend Status tag_invoke(json::value_to_tag<Status>,
                                    json::value const& v) {
            using namespace boost::spirit::x3;
    
            static const struct S : symbols<Status> {
                S() { this->add
                    ("accepted", Status::Accepted)
                    ("rejected", Status::Rejected)
                    ("pending", Status::Pending);
                }
            } _sym;
    
            Status result;
            auto& str = v.as_string();
    
            if (not phrase_parse(str.begin(), str.end(), no_case[_sym] >> eoi,
                                 space, result))
                throw std::domain_error("Status");
            return result;
        }
        friend Insurance tag_invoke(json::value_to_tag<Insurance>,
                                    json::value const& v) {
            auto& o = v.as_object();
            return {
                std::atol(o.at("currentYear").as_string().data()),
                o.at("accidents").as_int64(),
                Status{}
            };
        }
    };
    
    json::value make_array(auto&& range) {
        return json::array(range.begin(), range.end());
    }
    
    int main() {
        auto data = boost::json::parse(R"(
            [10, 
            "Session",
            {"currentYear":"2048","accidents":10,"status":"Accepted"},
            {"currentYear":"2049","accidents":11,"status":" rejected"},
            {"currentYear":"2050","accidents":12,"status":"Accepted"},
            {"currentYear":"2051","accidents":13,"status":"pendinG"},
            12,
            "Session"
        ]
        )").as_array();
    
        auto objects = make_array(data | filtered(std::mem_fn(&json::value::is_object)));
    
        auto vec = json::value_to<std::vector<Insurance>>(objects);
    
        for (Insurance const& obj : vec) {
            std::cout << "Year: " << obj.currentYear
                      << " Accidents:" << obj.accidents << std::endl;
        }
    }
    

    Prints

    Year: 2048 Accidents:10
    Year: 2049 Accidents:11
    Year: 2050 Accidents:12
    Year: 2051 Accidents:13