Search code examples
c++jsonc++11c++14nlohmann-json

nlohmann json parsing key and value to a class


I have the following data file

{
   "France": {
      "capital": "paris",
      "highpoint": "20",
    },
   "Germany": {
      "size": "20",
      "population": "5000"
    }
}

I am using nlohmann/json to parse it

I need to parse it into a country class

country.h

class Country {
public:
  friend void to_json(json &j , const Country &c);
  friend void from_json(const json &j , Country &c); 
private:
  std::string _name; 
  std::map _detail; 

to_json and from_json implementation

  to_json(json &j, const Country &c) {
    j = json{{c._name, c._detail}};

  void from_json(const json& j, Item& cat){
    auto c = j.get<std::map<std::string, std::map<std::string, std::string>>>();
    cat._id = c.begin()->first;
    cat._entry = c.begin()->second;

when i try to get the country from the json it does not work like this

  std::ifstream in("pretty.json");
  json j = json::parse(in);
  Country myCountry = j.get<Country>(); 

I have looked at the documentation the only i see to create the from_json is by knowing the key before hand see doc

j.at("the_key_name").get_to(country._name);

is there a way i could parse it without knowing the key ? in the from_json method ?


Solution

  • I think you need to customise to/from JSON for a vector of Country instead of the individual objects.

    You need to parse the outer object in the JSON file and add the name to each of the objects before parsing the inner map values.

    #include <map>
    #include <string>
    #include "nlohmann/json.hpp"
    #include <sstream>
    #include <iostream>
    
    using nlohmann::json;
    
    class Country {
    public:
      friend void to_json(json& j, const std::vector<Country>& value);
      friend void from_json(const json& j, std::vector<Country>& value);
    private:
      std::string _name;
      std::map<std::string, std::string> _detail;
    };
    
    void to_json(json& j, const std::vector<Country>& value)
    {
      for (auto& c : value)
      {
        j[c._name] = c._detail;
      }
    }
    
    void from_json(const json& j, std::vector<Country>& value)
    {
      for (auto& entry : j.items())
      {
        Country c;
        c._name = entry.key();
        c._detail = entry.value().get<std::map<std::string, std::string>>();
        value.push_back(c);
      }
    }
    
    int main()
    {
      try
      {
        std::stringstream in(R"({
       "France": {
          "capital": "paris",
          "highpoint": "20"
        },
       "Germany": {
          "size": "20",
          "population": "5000"
        }
    })");
        json j = json::parse(in);
        std::vector<Country> myCountry = j.get<std::vector<Country>>();
        json out = myCountry;
        std::cout << out.dump(2);
      }
      catch (std::exception& ex)
      {
        std::cout << ex.what() << "\n";
      }
    }
    

    Note that the JSON you gave in the question was not valid JSON.

    Try to avoid the use of friend functions, it'd be better to add getters and setters and a constructor to the class instead.