Bootstrap

【nlohmann/json】树节点的序列化和反序列化

nlohmann/json官方网站
https://github.com/nlohmann/json
https://json.nlohmann.me/api/basic_json/

背景

2022.09

nlohmann/json官方序列化,提供了宏NLOHMANN_DEFINE_TYPE_INTRUSIVE;
它支持多层嵌套,但对于指针无法序列化;
实际上这个宏定义就是在class中增加了to_json和from_json函数,我们可以自己去实现一下即可;
在这里插入图片描述

示例

TreeNode.hpp

class TreeNode;

using TreeNodePtr = std::shared_ptr<TreeNode>;

using ShaJson = nlohmann::json;

class TreeNode {
public:
    std::string id;
    std::string name;
    std::list<TreeNodePtr> children;

    friend void to_json(nlohmann::json& nlohmann_json_j, const TreeNode& nlohmann_json_t)
    {
        nlohmann_json_j["id"] = nlohmann_json_t.id;
        nlohmann_json_j["name"] = nlohmann_json_t.name;
        nlohmann_json_j["children"] = nlohmann::json::array();

        for(TreeNodePtr x : nlohmann_json_t.children)
        {
            std::cout << x->name << std::endl;

            nlohmann::json jsonTemp;

            to_json(jsonTemp, *x);

            nlohmann_json_j["children"].push_back(jsonTemp);
        }
    }

    friend void from_json(const nlohmann::json& nlohmann_json_j, TreeNode& nlohmann_json_t)
    {
        nlohmann_json_t.id = nlohmann_json_j.at("id");
        nlohmann_json_t.name = nlohmann_json_j.at("name");
        nlohmann::json arrayTemp =  nlohmann::json::array();
        arrayTemp = nlohmann_json_j.at("children");

        for (nlohmann::json& el : arrayTemp) {
            TreeNodePtr treeNode(new TreeNode());
            from_json(el, *treeNode);
            nlohmann_json_t.children.push_back(treeNode);
        }
    }
};

测试代码


int main() {
    std::cout << "Hello, World!" << std::endl;

    TreeNodePtr treeNode(new TreeNode());
    treeNode->name = "node1";
    TreeNodePtr treeNode2(new TreeNode());
    treeNode2->name = "node2";
    TreeNodePtr treeNode3(new TreeNode());
    treeNode3->name = "node3";

    treeNode->children.push_back(treeNode2);
    treeNode2->children.push_back(treeNode3);

    ShaJson json = *treeNode;

    std::cout << json.dump(4) << std::endl;

    json = ShaJson::parse(json.dump());

    TreeNodePtr temp(new TreeNode());

    *temp = json.get<TreeNode>();

    std::cout << json.dump(4) << std::endl;

    return 0;
}

智能指针支持

FuncInfo.hpp

实体类

class FuncInfo {
public:
    std::string funcId;
    std::string funcName;
    std::string parentId;
};

using FuncInfoPtr = std::shared_ptr<FuncInfo>;

FuncTreeNode.hpp


class FuncTreeNode;

using FuncTreeNodePtr = std::shared_ptr<FuncTreeNode>;

class FuncTreeNode {
public:
    std::string funcId;
    std::string funcName;
    std::string parentId;
    std::vector<FuncTreeNodePtr> childFuncs;

    static FuncTreeNodePtr createTree(std::vector<FuncInfoPtr> &funcInfos, FuncTreeNodePtr root){
        std::vector<FuncTreeNodePtr> children;

        for(FuncInfoPtr x : funcInfos){
            if(x->parentId == root->funcId){
                children.push_back(createTree(funcInfos, x));
            }
        }

        root->childFuncs = children;

        return root;
    }

    static std::vector<FuncTreeNodePtr> createForest(std::vector<FuncInfoPtr> funcInfos) {
        // 存放多个根节点
        std::vector<FuncTreeNodePtr> rootList;

        // 找到根节点,并放到rootList中
        for (int i = 0; i < funcInfos.size(); i++) {
            bool hasParent = false;
            for (int j = 0; j < funcInfos.size(); j++) {
                if (funcInfos[i]->parentId == funcInfos[j]->funcId) {
                    hasParent = true;
                    break;
                }
            }
            if (hasParent == false) {
                FuncTreeNodePtr root(new FuncTreeNode());
                root->funcId = funcInfos[i]->funcId;
                root->parentId = funcInfos[i]->parentId;
                root->funcName = funcInfos[i]->funcName;

                rootList.push_back(root);
            }
        }

        // 从每个根节点开始构建树
        for(FuncTreeNodePtr root : rootList){
            createTree(funcInfos, root);
        }

        return rootList;
    }

    // 序列化
    friend void to_json(nlohmann::json& nlohmann_json_j, const FuncTreeNode& nlohmann_json_t)
    {
        nlohmann_json_j["funcId"] = nlohmann_json_t.funcId;
        nlohmann_json_j["funcName"] = nlohmann_json_t.funcName;
        nlohmann_json_j["childFuncs"] = nlohmann::json::array();

        for(FuncTreeNodePtr x : nlohmann_json_t.childFuncs)
        {
            nlohmann::json jsonTemp;

            to_json(jsonTemp, *x);

            nlohmann_json_j["childFuncs"].push_back(jsonTemp);
        }
    }

    friend void from_json(const nlohmann::json& nlohmann_json_j, FuncTreeNode& nlohmann_json_t)
    {
        nlohmann_json_t.funcId = nlohmann_json_j.at("funcId");
        nlohmann_json_t.funcName = nlohmann_json_j.at("funcName");
        nlohmann::json arrayTemp =  nlohmann::json::array();
        arrayTemp = nlohmann_json_j.at("childFuncs");

        for (nlohmann::json& el : arrayTemp) {
            FuncTreeNodePtr treeNode(new FuncTreeNode());
            from_json(el, *treeNode);
            nlohmann_json_t.childFuncs.push_back(treeNode);
        }
    }

    // 智能指针版本
    friend void to_json(nlohmann::json& nlohmann_json_j, const FuncTreeNodePtr nlohmann_json_t)
    {
        nlohmann_json_j["funcId"] = nlohmann_json_t->funcId;
        nlohmann_json_j["funcName"] = nlohmann_json_t->funcName;
        nlohmann_json_j["childFuncs"] = nlohmann::json::array();

        for(FuncTreeNodePtr x : nlohmann_json_t->childFuncs)
        {
            nlohmann::json jsonTemp;

            to_json(jsonTemp, *x);

            nlohmann_json_j["childFuncs"].push_back(jsonTemp);
        }
    }

    friend void from_json(const nlohmann::json& nlohmann_json_j, FuncTreeNodePtr nlohmann_json_t)
    {
        nlohmann_json_t->funcId = nlohmann_json_j.at("funcId");
        nlohmann_json_t->funcName = nlohmann_json_j.at("funcName");
        nlohmann::json arrayTemp =  nlohmann::json::array();
        arrayTemp = nlohmann_json_j.at("childFuncs");

        for (nlohmann::json& el : arrayTemp) {
            FuncTreeNodePtr treeNode(new FuncTreeNode());
            from_json(el, *treeNode);
            nlohmann_json_t->childFuncs.push_back(treeNode);
        }
    }
};

测试代码

森林

int main() {
    std::cout << "Hello, World!" << std::endl;

    //StringUtils::test20220925();
    FuncTreeNodePtr ptr1(new FuncTreeNode());
    ptr1->funcName = "node1";
    FuncTreeNodePtr ptr2(new FuncTreeNode());
    ptr2->funcName = "node2";
    FuncTreeNodePtr ptr3(new FuncTreeNode());
    ptr3->funcName = "node3";

    ptr1->childFuncs.push_back(ptr2);
    ptr2->childFuncs.push_back(ptr3);

    ShaJson json = *ptr1;

    //std::cout << json.dump() << std::endl;

    std::vector<FuncInfoPtr> funcInfos;
    FuncInfoPtr funcInfoPtr1(new FuncInfo());
    funcInfoPtr1->funcId = "1";
    funcInfoPtr1->parentId = "-1";
    FuncInfoPtr funcInfoPtr2(new FuncInfo());
    funcInfoPtr2->funcId = "2";
    funcInfoPtr2->parentId = "-1";
    FuncInfoPtr funcInfoPtr3(new FuncInfo());
    funcInfoPtr3->funcId = "3";
    funcInfoPtr3->parentId = "2";
    FuncInfoPtr funcInfoPtr4(new FuncInfo());
    funcInfoPtr4->funcId = "4";
    funcInfoPtr4->parentId = "3";

    funcInfos.push_back(funcInfoPtr1);
    funcInfos.push_back(funcInfoPtr2);
    funcInfos.push_back(funcInfoPtr3);
    funcInfos.push_back(funcInfoPtr4);

    std::vector<FuncTreeNodePtr> forest = FuncTreeNode::createForest(funcInfos);

    std::string str;
    str += "[";

    for(FuncTreeNodePtr x : forest)
    {
        ShaJson jsonOut = *x;
        str += jsonOut.dump();
        str += ",";
    }

    str += "]";

    std::cout << str << std::endl;

    ShaJson jsonx = forest;

    std::cout << jsonx.dump() << std::endl;

    return 0;
}

输出
Hello, World!
[{“childFuncs”:[],“funcId”:“1”,“funcName”:“”},{“childFuncs”:[{“childFuncs”:[{“childFuncs”:[],“funcId”:“4”,“funcName”:“”}
],“funcId”:“3”,“funcName”:“”}],“funcId”:“2”,“funcName”:“”},]
[{“childFuncs”:[],“funcId”:“1”,“funcName”:“”},{“childFuncs”:[{“childFuncs”:[{“childFuncs”:[],“funcId”:“4”,“funcName”:“”}
],“funcId”:“3”,“funcName”:“”}],“funcId”:“2”,“funcName”:“”}]

json结构

[
    {
        "childFuncs":[

        ],
        "funcId":"1",
        "funcName":""
    },
    {
        "childFuncs":[
            {
                "childFuncs":[
                    {
                        "childFuncs":[

                        ],
                        "funcId":"4",
                        "funcName":""
                    }
                ],
                "funcId":"3",
                "funcName":""
            }
        ],
        "funcId":"2",
        "funcName":""
    }
]
;