【问题标题】:nlohmann json, converting to and from nested structuresnlohmann json,在嵌套结构之间转换
【发布时间】:2020-05-10 06:51:52
【问题描述】:

我将nlohmann json (JSON for modern C++) 用于嵌入式项目。操作系统是猫鼬操作系统。 Mongoose 有一个很好的配置系统,其中配置数据在 mos.yml 文件中进行处理和布局。该文件在构建时被转换为结构和访问器函数。因此,我可以将配置数据作为一个结构获取,其中包含其他嵌套结构。我需要将其转换为 JSON。

我的理解是 nlohmann::json 能够将 JSON 转换为我自己的类型,我所要做的就是提供 to_json()from_json() 方法,如下所述:

nlohmann json docs (type conversion example)

此示例代码非常简单:

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;
};

如果有人能告诉我它是如何完成的或指出正确的方向,将不胜感激,谢谢。

【问题讨论】:

    标签: c++ json c++11 nlohmann-json


    【解决方案1】:

    这是一个嵌套类型的示例,其中为合并类型 Person (live) 定义了 to_json

    #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 示例 (live):

    #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"
            }
        }
    ]
    

    【讨论】:

    • 感谢 Azeem,我无法让您的第一个示例正常运行。似乎该库正在制作多个 since 对象数组。你能看看吗? godbolt.org/z/Y8kNrm
    • @JimArcher:不客气!您的 sn-p 的 JSON 预期输出是什么?
    • 大体相同,但没有方括号。它们似乎不需要,尽管我猜它们是无害的。如果那是正常的,那没关系,我只是以为我错误地使用了库。
    • @JimArcher:对。好吧,它们会阻碍您对复杂对象的解析,因为您必须记住这些是数组并且您需要使用索引。看看这个:godbolt.org/z/J6VpjV。我相信这就是你之前的意思。
    • 啊,是的,看起来不错!非常感谢,我试试看!
    猜你喜欢
    • 1970-01-01
    • 2015-12-11
    • 2017-03-21
    • 1970-01-01
    • 2021-08-26
    • 2021-04-13
    • 2020-01-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多