如何在JSON中引用其他值以避免重复粘贴?
解决nlohmann::json中JSON引用$ref的问题
nlohmann::json库本身不原生支持JSON Schema的$ref引用自动解析,所以直接写$ref的话,它只会把这个当作普通的键值对(一个包含"$ref"键的对象),不会自动替换成目标值。你可以通过以下几种方式解决:
1. 手动实现$ref解析逻辑
自己写递归函数遍历JSON结构,识别带有$ref的字段,根据引用路径找到目标值并替换。
比如针对你的场景,示例代码如下:
#include <nlohmann/json.hpp> #include <vector> #include <string> #include <iostream> using json = nlohmann::json; // 递归解析$ref引用 void resolve_refs(json& target, const json& root) { if (target.is_object()) { // 检查当前对象是否是$ref引用 if (target.contains("$ref") && target["$ref"].is_string()) { std::string ref_path = target["$ref"].get<std::string>(); // 处理#/xxx/yyy格式的引用路径 if (ref_path.substr(0, 2) == "#/") { std::vector<std::string> path_parts; size_t pos = 2; while (pos < ref_path.size()) { size_t slash_pos = ref_path.find('/', pos); if (slash_pos == std::string::npos) { path_parts.push_back(ref_path.substr(pos)); break; } path_parts.push_back(ref_path.substr(pos, slash_pos - pos)); pos = slash_pos + 1; } // 从根节点开始查找目标值 const json* current_node = &root; bool valid_ref = true; for (const auto& part : path_parts) { if (current_node->contains(part)) { current_node = &(*current_node)[part]; } else { valid_ref = false; break; } } // 替换引用为目标值(如果引用有效) if (valid_ref) { target = *current_node; } } } else { // 递归处理对象的每个子字段 for (auto& [key, value] : target.items()) { resolve_refs(value, root); } } } else if (target.is_array()) { // 递归处理数组的每个元素 for (auto& elem : target) { resolve_refs(elem, root); } } } int main() { // 你的示例JSON json raw_data = R"( { "loggingFile": "archive.txt", "someKey": [ { "name": "task1", "loggingFile": {"$ref": "#/loggingFile"} }, { "name": "task2", "loggingFile": {"$ref": "#/loggingFile"} } ] } )"_json; // 解析所有引用 resolve_refs(raw_data, raw_data); // 输出处理后的结果 std::cout << raw_data.dump(4) << std::endl; return 0; }
这段代码会遍历JSON的所有节点,把带有$ref的对象替换成对应的目标值,处理后someKey数组里的每个loggingFile字段都会变成"archive.txt"字符串。
2. 预处理JSON文件
如果不想在代码里处理,可以用支持JSON Schema引用的工具提前把带$ref的JSON展开成普通JSON,再用nlohmann::json读取。比如用Python的jsonschema库或者专门的JSON引用展开工具,提前生成没有引用的JSON文件。
3. 使用自定义标识代替$ref
如果不想依赖$ref规范,可以自己定义一个标识(比如"__ref__"),然后在代码里识别这个键并替换。这样可以避免和任何库的默认行为冲突,逻辑和上面的手动解析类似,只是把判断"$ref"改成判断"__ref__"即可。
内容的提问来源于stack exchange,提问作者CagesThrottleUs
相关产品推荐
相关产品推荐

