Home > Enterprise >  Convert JSON to array with nlohmann/json
Convert JSON to array with nlohmann/json

Time:02-13

I've not used C in over 20 years, so I am a bit rusty on this.

I am using the nlohmann/json json.h library and need to convert a JSON string that is an array of objects to an actual array.

As an example, I need to take this kind of response from a TRESTResponse object and turn it into a C array:

RESTRequest1->Execute();
String Content = RESTResponse1->Content;

Where Content =

"[{"fullname":"Norm A","e_mail":null,"phone":"999-555-4971"},{"fullname":"Norm C","e_mail":"[email protected]","phone":"999-555-8887"},{"fullname":"Norma Jn","e_mail":null,"phone":"999-555-5947"},{"fullname":"Norma & Frank L","e_mail":null,"phone":"999-555-1790"},{"fullname":"Norm Sh","e_mail":null,"phone":"999-555-7545"},{"fullname":"Norm S","e_mail":null,"phone":"999-555-9955"}]"

and get it into an array of objects. I have been unsuccessful with the library. While I can get an array into json properly, I can't seem to get json back to an array.

I've looked at some similar posts on Stackoverflow, but I did not see one that concerns the nlohmann/json library.

CodePudding user response:

[EDIT] Added an example that uses your input data. [Demo]

// Outputs:
//
//   [
//     (Norm A, null, 999-555-4971),
//     (Norm C, [email protected], 999-555-8887),
//     (Norma Jn, null, 999-555-5947),
//     (Norma & Frank L, null, 999-555-1790),
//     (Norm Sh, null, 999-555-7545),
//     (Norm S, null, 999-555-9955)
//   ]

The example below loads a JSON node of array type into a std::vector.

The input JSON string only contains a node writers whose content is an array of strings:

{
    "writers": [
        "Winston Groom",
        "Eric Roth"
    ]
}

We load it into a JSON node with:

nlohmann::json j = nlohmann::json::parse(json_str);

We parse the "value" for the writers "key", i.e. the array, with:

j.at("writers").get_to(writers);

This will make use of the available from_json(const nlohmann::json&, YourCustomType&) in order to do the parsing.

The struct Writers parses the JSON node into a std::vector<Writer> with:

    writers.data = j.get<std::vector<Writer>>();

And the struct Writer parses the JSON node into a std::string with:

    j.get_to(writer.name);

[Demo]

#include <iostream>  // cout
#include <nlohmann/json.hpp>
#include <ostream>
#include <string>
#include <vector>

struct Writer
{
    std::string name{};
};
void from_json(const nlohmann::json& j, Writer& writer)
{
    j.get_to(writer.name);
}

struct Writers
{
    std::vector<Writer> data{};
};
void from_json(const nlohmann::json& j, Writers& writers)
{
    writers.data = j.get<std::vector<Writer>>();
}

int main()
{
    std::string json_str{R"({"writers": ["Winston Groom", "Eric Roth"]})"};
    Writers writers{};
    nlohmann::json j = nlohmann::json::parse(json_str.c_str());
    j.at("writers").get_to(writers);

    for (const auto& writer : writers.data)
    {
        std::cout << writer.name << ", ";
    }
}

// Outputs:
//
//   Winston Groom, Eric Roth,

CodePudding user response:

At a guess, you were probably running into a problem because your input data contains null for a number of the strings (some of the email addresses).

To fix that, you need to explicitly check for is_null before attempting to convert the source to an std::string. At a quick guess, for a null input, you'd probably want to just leave that string empty. For that, your from_json would look something like this:

void from_json(json const &j, Person &p) { 
    j.at("fullname").get_to(p.name);
    if (!j.at("e_mail").is_null())
        j.at("e_mail").get_to(p.email);
    j.at("phone").get_to(p.phone);
}

That's enough to work for the sample data, but depending on the data involved, you might want/need to protect against a null name and/or phone numbers as well (which you'd do in the same way as shown above for the email address).

A complete demo program using this would might look roughly like this:

#include <sstream>
#include <string>
#include <iostream>
#include "nlohmann/json.hpp"

using json = nlohmann::json;

std::string input { R"(
[{"fullname":"Norm A","e_mail":null,"phone":"999-555-4971"},{"fullname":"Norm C","e_mail":"[email protected]","phone":"999-555-8887"},{"fullname":"Norma Jn","e_mail":null,"phone":"999-555-5947"},{"fullname":"Norma & Frank L","e_mail":null,"phone":"999-555-1790"},{"fullname":"Norm Sh","e_mail":null,"phone":"999-555-7545"},{"fullname":"Norm S","e_mail":null,"phone":"999-555-9955"}]
)"};

namespace P {
struct Person { 
    std::string name;
    std::string email;
    std::string phone;

    friend std::ostream &operator<<(std::ostream &os, Person const &p) { 
        return os << "name: " << p.name << ", email: " << p.email << ", phone: " << p.phone;
    }
};

void from_json(json const &j, Person &p) { 
    j.at("fullname").get_to(p.name);
    if (!j.at("e_mail").is_null())
        j.at("e_mail").get_to(p.email);
    j.at("phone").get_to(p.phone);
}
}

int main() { 
    json j = json::parse(input);

    std::vector<P::Person> people;
    
    j.get_to(people);

    for (auto const &person : people) {
        std::cout << person << "\n";
    }
}
  • Related