如何访问TMDB JSON数据中的数组元素(基于nlohmann::json)
nlohmann::json解析TMDB数组字段返回空的解决方法
问题场景
从TMDB获取JSON数据并存储到本地后,使用nlohmann::json库解码时,string、boolean等基础类型处理正常,但处理genres这类数组字段时,调用array()方法返回空数组,无法读取内部元素。需要将genres数组中的name字段用;拼接,生成genres = Abenteuer;Action的INI格式内容。
相关代码与输出
遍历JSON根节点的代码:
using json = nlohmann::json; { auto jsonData = json::parse(jsonText); // std::cout << jsonData.dump(1) << "\n"; for (const auto &jsonItem : jsonData.items()) { std::string jsonKey = jsonItem.key(); std::string jsonValue = ""; if (jsonItem.value().is_null()) { jsonValue = "(null)"; } else if (jsonItem.value().is_boolean()) { jsonValue = jsonItem.value() ? "(boolean) yes" : "(boolean) no"; } else if (jsonItem.value().is_string()) { jsonValue = "(string) '" + string_left(jsonItem.value(), 25) + "'"; } // ... 其他类型处理 std::cout << jsonKey << ": " << jsonValue << "\n"; } }
屏幕输出片段:
adult: (boolean) no belongs_to_collection: (null) budget: (unsigned) 45000000 credits: (object) genres: (array) [ . . . ]
原处理genres数组的代码及输出:
else if (jsonItem.key() == "genres") // array { std::cout << " jsonItem: " << jsonItem << "\n"; // {"genres":[{"id":12,"name":"Abenteuer"},{"id":28,"name":"Action"}]} jsonKey = jsonItem.key(); std::cout << " jsonKey: " << jsonKey << "\n"; // genres auto jsonValueArray = jsonItem.value().array(); std::cout << " jsonValueArray: " << jsonValueArray << " (" << sizeof(jsonValueArray) << ")\n"; // [] (16) auto jsonValueFlat = jsonItem.value().flatten(); std::cout << " jsonValueFlat: " << jsonValueFlat << "\n"; // {"/0/id":12,"/0/name":"Abenteuer","/1/id":28,"/1/name":"Action"} std::cout << " " << jsonKey << " elements: " << jsonValueArray.size() << "\n"; // 0 // ... 遍历逻辑无输出 }
输出结果:
jsonItem: {"genres":[{"id":12,"name":"Abenteuer"},{"id":28,"name":"Action"}]} jsonKey: genres jsonValueArray: [] (16) jsonValueFlat: {"/0/id":12,"/0/name":"Abenteuer","/1/id":28,"/1/name":"Action"} genres elements: 0
解决方案
问题根源在于array()方法返回的是数组视图(nlohmann::json::array_t),直接赋值可能导致视图失效。正确的做法是直接遍历数组类型的json对象本身,无需调用array()。
正确的数组处理代码
方式1:拼接成单个INI字段(符合需求)
else if (jsonItem.key() == "genres") { std::vector<std::string> genreNames; // 直接遍历数组类型的json值 for (const auto& genreObj : jsonItem.value()) { // 安全检查字段是否存在 if (genreObj.contains("name")) { genreNames.push_back(genreObj["name"].get<std::string>()); } } // 用;拼接所有分类名称 std::string joinedGenres; for (size_t i = 0; i < genreNames.size(); ++i) { if (i != 0) { joinedGenres += ";"; } joinedGenres += genreNames[i]; } // 写入INI格式内容 iniText.append(jsonItem.key()); iniText.append(" = "); iniText.append(joinedGenres); iniText.append("\n"); // 调试输出 std::cout << " 拼接结果: " << joinedGenres << "\n"; }
方式2:生成单个GenreX条目(可选)
如果需要生成Genre0 = Abenteuer、Genre1 = Action这类条目,可修改遍历逻辑:
else if (jsonItem.key() == "genres") { size_t index = 0; for (const auto& genreObj : jsonItem.value()) { if (genreObj.contains("name")) { std::string iniKey = "Genre" + std::to_string(index); std::string iniValue = genreObj["name"].get<std::string>(); iniText.append(iniKey); iniText.append(" = "); iniText.append(iniValue); iniText.append("\n"); index++; } } }
核心说明
- 直接遍历json对象:数组类型的nlohmann::json实例支持范围for循环遍历,无需额外转换为数组视图。
- 安全字段访问:使用
contains()检查字段是否存在,避免因JSON结构变化导致的异常。 - 类型转换:通过
get<std::string>()将json字符串值转换为C++标准字符串,确保类型安全。
内容的提问来源于stack exchange,提问作者Michael Rittweger
相关产品推荐
相关产品推荐

