+-
nlohmann json,从嵌套结构转换到嵌套结构。

我用的是 nlohmann json(现代C++的JSON)。 与一个嵌入式项目。操作系统是Mongoose OS。Mongoose有一个很好的配置系统,配置数据在mos.yml文件中被处理和布局。这个文件,在构建时,会被转换为结构体和访问函数。所以,我可以把config数据作为一个结构,其中包含其他的、嵌套的结构。我需要将其转换为JSON。

我的理解是,nlohmann::json有能力将JSON转换为我自己的类型,我所要做的就是提供以下信息 to_json()from_json() 方法,如这里的解释。

nlohmann json docs (类型转换示例)

这个例子代码非常简单。

struct person {
    std::string name;
    std::string address;
    int age;
};

void to_json(json& j, const person& p) {
    j = json{{"name", p.name}, {"address", p.address}, {"age", p.age}};
}

但这个例子非常简单。我的类型比较复杂,我一直没有搞清楚像这个比较复杂的结构的语法(为简洁起见摘录)。

struct mgos_config_mytype {
  struct mgos_config_mytype_input input;
  struct mgos_config_mytype_speed speed;

  /* many others omitted */

};

struct mgos_config_mytype_input {
  struct mgos_config_mytype_input_wired_buttons wired_buttons;
};

struct mgos_config_mytype_input_wired_buttons {
  const char * btn1;
  const char * btn2;
  const char * btn3;
};

如果有人能告诉我是怎么做的,或者指出正确的方向,我将感激不尽,谢谢你。

0
投票

这里有一个嵌套类型的例子,有 to_json 为综合类定义的 Person (住):

#include <iostream>
#include <string>

#include <nlohmann/json.hpp>
using nlohmann::json;

struct Name
{
    std::string first;
    std::string last;
};

struct Address
{
    std::string houseNo;
    std::string street;
    std::string city;
    std::string postalCode;
    std::string country;
};

struct Person
{
    Name    name;
    Address address;
    int     age;
};

void to_json(json& j, const Person& p)
{
    j = json{
        { "name", {
            { "first", p.name.first },
            { "last", p.name.last }
            } 
        },
        { "address", {
            { "house", p.address.houseNo },
            { "street", p.address.street },
            { "city", p.address.city },
            { "postal_code", p.address.postalCode },
            { "country", p.address.country }
            }
        },
        { "age", p.age}
    };
}

int main()
{
    const Person p { 
        { "firstname", "lastname" }, 
        { "123", "St. ABC", "XYZ", "123456", "country" }, 
        18
    };

    json j { p };
    std::cout << j.dump(4) << '\n';

    return 0;
}

输出。

[
    {
        "address": {
            "city": "XYZ",
            "country": "country",
            "house": "123",
            "postal_code": "123456",
            "street": "St. ABC"
        },
        "age": 18,
        "name": {
            "first": "firstname",
            "last": "lastname"
        }
    }
]

根据嵌套类型的复杂度和可重用性,你可以定义出 to_jsonfrom_json 的所有类型。

这里是Person-to-JSON和JSON-to-Person的例子(住):

#include <iostream>
#include <string>

#include <nlohmann/json.hpp>
using nlohmann::json;

struct Name
{
    std::string first;
    std::string last;
};

struct Address
{
    std::string houseNo;
    std::string street;
    std::string city;
    std::string postalCode;
    std::string country;
};

struct Person
{
    Name    name;
    Address address;
    int     age;
};

void to_json(json& j, const Name& name)
{
    j = json{
        { "first", name.first },
        { "last", name.last }
    };
}

void from_json(const json& j, Name& name)
{
    j.at("first").get_to(name.first);
    j.at("last").get_to(name.last);
}

void to_json(json& j, const Address& address)
{
    j = json{
        { "house", address.houseNo },
        { "street", address.street },
        { "city", address.city },
        { "postalCode", address.postalCode },
        { "country", address.country }
    };
}

void from_json(const json& j, Address& address)
{
    j.at("house").get_to(address.houseNo);
    j.at("street").get_to(address.street);
    j.at("street").get_to(address.street);
    j.at("city").get_to(address.city);
    j.at("postalCode").get_to(address.postalCode);
    j.at("country").get_to(address.country);
}

void to_json(json& j, const Person& p)
{
    j = json{
        { "name", p.name },
        { "address", p.address },
        { "age", p.age }
    };
}

void from_json(const json& j, Person& p)
{
    j.at("name").get_to(p.name);
    j.at("address").get_to(p.address);
    j.at("age").get_to(p.age);
}

int main()
{
    const Person p1 { 
        { "firstname", "lastname" }, 
        { "123", "St. ABC", "XYZ", "123456", "country" }, 
        18
    };

    const json j1 { p1 };               // Get JSON object from Person
    const auto s1 = j1.dump(4);         // Get JSON string with indentation (4 spaces)
    std::cout << s1 << '\n';

    auto p2 = j1[0].get<Person>();      // Get Person object from JSON array
    p2.name = { "ABC", "XYZ" };         // Update first and last names

    const json j2 { p2 };               // Get JSON object from Person
    const auto s2 = j2.dump(4);         // Get JSON string with indentation (4 spaces)
    std::cout << s2 << '\n';


    return 0;
}

输出:

[
    {
        "address": {
            "city": "XYZ",
            "country": "country",
            "house": "123",
            "postalCode": "123456",
            "street": "St. ABC"
        },
        "age": 18,
        "name": {
            "first": "firstname",
            "last": "lastname"
        }
    }
]
[
    {
        "address": {
            "city": "XYZ",
            "country": "country",
            "house": "123",
            "postalCode": "123456",
            "street": "St. ABC"
        },
        "age": 18,
        "name": {
            "first": "ABC",
            "last": "XYZ"
        }
    }
]