skip to Main Content

This is my first time using the library (nlohmann / json) and I have a question.

I wanted to write a valid JSON file from objects that I organize using a std::vector.

For this I have thought of a simple example (see below).

Now, however, I have problems writing the data out of the JSON structure into the JSON file.
Something is missing from me at the moment.
Maybe I have a misconception…

Somehow I’m missing "1 JSON level" (myCars).
A general question is whether I can generate the entire file content from a single JSON structure (here j)?
(Or does that have to be chopped up over many JSON structures?)

Please also have a look at the following source code.
At the top I wrote the content of the JSON file as I would like it to be.
Unfortunately, I can’t get to my goal here (with iterating over the std::vector).

I would be very grateful for tips/suggestions.
Thank you very much.

#include <iostream>
#include <fstream>
#include <string>

#include <json.h>
using json = nlohmann::json;

/* This is the JSON file I want to generate from std::vector<car> myGarage (as source)
{ 
    "myCars": {
        "car1" : {
            "Color": "red",
            "Price": 10000,
            "Speed": 200
            },
        "car2" : {
            "Color": "blue",
            "Price": 16000,
            "Speed": 666
            },
        "car3" : {
            "Color": "yellow",
            "Price": 7500,
            "Speed": 50
            },
        "car4" : {
            "Color": "green",
            "Price": 750,
            "Speed": 10
        }
    }
}
*/

class car
{
public:
    car(std::string color, uint16_t speed, uint32_t price) : 
        m_color(color),
        m_speed(speed),
        m_price(price){};

    std::string getColor(){return m_color;};
    uint16_t getSpeed(){return m_speed;};
    uint32_t getPrice(){return m_price;};
private:
    std::string m_color;
    uint16_t    m_speed;
    uint32_t    m_price;
};

int main() 
{
    std::vector<car> myGarage;
    myGarage.emplace_back("red", 200, 10000);
    myGarage.emplace_back("blue", 666, 16000);
    myGarage.emplace_back("yellow", 50, 7500);
    myGarage.emplace_back("green", 10, 750);

    std::ofstream outputJSONfile("pretty.json");
    // create an empty structure (null)
    
    json j;

    for( auto oneCar : myGarage)
    {
        j.emplace("Color", oneCar.getColor() );
        j.emplace("Speed", oneCar.getSpeed() );
        j.emplace("Price", oneCar.getPrice() );
        
    }
    outputJSONfile << std::setw(4) << j << std::endl;
    outputJSONfile.flush();

    return 0;
}

2

Answers


  1. You can use operator[] to get and set object key-value pairs, and you can use the brace-initializer form to create an object from a static list of key-value pairs:

        json myCars;
        int counter = 1;
        for( auto oneCar : myGarage)
        {
            std::string key = "car" + std::to_string(counter++);
            myCars[key] = json{{"Color", oneCar.getColor() },{"Speed", oneCar.getSpeed() }, {"Price", oneCar.getPrice() }};
        }
        json output{{"myCars", myCars}};
        outputJSONfile << std::setw(4) << output << std::endl;
        outputJSONfile.flush();
    
    Login or Signup to reply.
  2. It does not give you exactly the JSON structure you ask for (array instead of "car1, "car2"…), but here is a simple example of how to serialize and deserialize a vector of objects to and from JSON:

    struct Car
    {
        std::string color;
        int price;
        int speed;
    };
    
    // This is a macro in nlohmann::json that defines to_json and from_json methods for Car
    NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Car, color, price, speed)
    
    int main()
    {
        std::vector<Car> carList{
            {.color = "red", .price = 10000, .speed = 200},
            {.color = "blue", .price = 16000, .speed = 666},
            {.color = "yellow", .price = 7500, .speed = 50},
            {.color = "green", .price = 750, .speed = 10}};
    
        nlohmann::json j = carList; // This line turns the vector to JSON
    
        std::string jsonString = j.dump(); // JSON dumped to string
        std::cout << jsonString << 'n';
    
        // Parsing to string back to a vector of Car objects
        std::vector<Car> newList = nlohmann::json::parse(jsonString);
    
        for (const auto &c : newList)
            std::cout << c.color << ", " << c.price << ", " << c.speed << 'n';
    }
    

    This gives output:

    [{"color":"red","price":10000,"speed":200},{"color":"blue","price":16000,"speed":666},{"color":"yellow","price":7500,"speed":50},{"color":"green","price":750,"speed":10}]
    red, 10000, 200
    blue, 16000, 666
    yellow, 7500, 50
    green, 750, 10
    

    The NLOHMANN_DEFINE_... macro only works if you already have to_json and from_json methods for the member-types in your class (the library provides for int, std::string, std::vector, and most other standard types), but you can chain them so if you use it for your Car class, then that enables it for your struct Garage{Car car};.

    On the other hand, if you want to define your own to_json and from_json methods – f.ex. if you want to serialize an enum, then here is how

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search