ToB企服应用市场:ToB评测及商务社交产业平台
标题:
【Jsoncpp】manipulating JSON data in C++
[打印本页]
作者:
缠丝猫
时间:
2025-1-9 02:42
标题:
【Jsoncpp】manipulating JSON data in C++
源代码
#include <iostream> // 引入输入输出流库,用于标准输入输出操作
#include <fstream> // 引入文件流库,用于文件读写操作
#include <json/json.h> // 引入JSON库,用于解析和操作JSON数据
using namespace std; // 使用标准命名空间,避免每次调用标准库函数时都要加std::
int main()
{
Json::Value root; // 创建一个Json::Value对象,用于存储解析后的JSON数据
ifstream ifs; // 创建一个输入文件流对象,用于读取文件
ifs.open("profile.json"); // 打开名为"profile.json"的文件
Json::CharReaderBuilder builder; // 创建一个JSON解析器的构建器对象
builder["collectComments"] = true; // 设置解析器在解析时收集注释
JSONCPP_STRING errs; // 创建一个字符串对象,用于存储解析过程中可能产生的错误信息
// 使用解析器从文件流中解析JSON数据,并将结果存储在root对象中
// 如果解析失败,输出错误信息并返回EXIT_FAILURE
if (!parseFromStream(builder, ifs, &root, &errs))
{
std::cout << errs << std::endl; // 输出错误信息
return EXIT_FAILURE; // 返回程序失败状态
}
Json::Value::iterator itr = root.begin(); // 创建一个迭代器,指向JSON对象的起始位置
int i = 0; // 初始化一个计数器,用于遍历JSON对象的成员
string name; // 创建一个字符串对象,用于存储JSON对象的成员名称
// 遍历JSON对象的每个成员
for (itr = root.begin(); itr != root.end(); itr++)
{
name = root.getMemberNames()[i]; // 获取当前成员的名称
// 如果当前成员的值是一个数组(大小大于1),则遍历数组中的每个元素
if (root[name].size() > 1) {
for (auto x : root[name]) {
cout << name << ": " << x << endl; // 输出成员名称和数组中的每个元素
}
}
else {
cout << name + " "; // 输出成员名称
cout << root[name] << endl; // 输出成员的值
}
i++; // 计数器加1,准备处理下一个成员
}
}
复制代码
json内容为:
{"isbn": "123-456-789",
"author":
{
"lastname": "Doe",
"firstname" : "Jane"
},
"editor":
{
"lastname": "Smith",
"firstname": "Jane"
},
"title": "The Ultimate Database Study Guide",
"category": ["Non-Fiction", "Technology"]
}
复制代码
输出结果:
author: “Jane”
author: “Doe”
category: “Non-Fiction”
category: “Technology”
editor: “Jane”
editor: “Smith”
isbn “123-456-789”
title “The Ultimate Database Study Guide”
为什么没有按json顺序呢?
JSON 是一种无序的数据结构,Json::Value 在解析 JSON 文件时并不会保留原始的顺序。因此,当你遍历 Json::Value 对象时,成员的顺序可能与 JSON 文件中的顺序不一致。
原因分析:
JSON 的无序性
:
JSON 标准(RFC 8259)明确规定,JSON 对象中的键值对是无序的。解析器在解析 JSON 时,通常会使用某种数据结构(如哈希表)来存储键值对,而哈希表本身是无序的。
因此,Json::Value 在解析 JSON 文件时,不会保留键值对的原始顺序。
getMemberNames() 的顺序
:
在你的代码中,root.getMemberNames() 返回的是 JSON 对象的所有键(成员名称),但它们的顺序可能与 JSON 文件中的顺序差别。
这是因为 getMemberNames() 返回的顺序取决于 Json::Value 内部存储键值对的方式,而不是 JSON 文件中的顺序。
遍历顺序
:
当你使用 for (itr = root.begin(); itr != root.end(); itr++) 遍历 Json::Value 时,迭代器的顺序也是由 Json::Value 内部决定的,可能与 JSON 文件中的顺序不一致。
如何保持顺序?
如果你需要保持 JSON 文件中的原始顺序,可以尝试以下方法:
方法 1:使用有序的 JSON 库
某些 JSON 库支持有序的 JSON 解析。例如,nlohmann::json(一个盛行的 C++ JSON 库)可以保留 JSON 文件中的键值对顺序。
方法 2:手动指定顺序
如果你知道 JSON 文件的结构,可以手动指定遍历的顺序。例如:
std::vector<std::string> keys = {"isbn", "author", "editor", "title", "category"};
for (const auto& key : keys) {
if (root.isMember(key)) {
if (root[key].isArray()) {
for (const auto& item : root[key]) {
std::cout << key << ": " << item << std::endl;
}
} else {
std::cout << key << " " << root[key] << std::endl;
}
}
}
复制代码
方法 3:修改代码逻辑
如果你盼望按照 JSON 文件中的顺序输出,可以修改代码逻辑,直接按照 getMemberNames() 的顺序输出,而不是依赖迭代器:
for (size_t i = 0; i < root.size(); ++i) {
std::string name = root.getMemberNames()[i];
if (root[name].isArray()) {
for (const auto& item : root[name]) {
std::cout << name << ": " << item << std::endl;
}
} else {
std::cout << name << " " << root[name] << std::endl;
}
}
复制代码
为什么输出结果中嵌套对象被拆开?
在你的输出结果中,author 和 editor 被拆开为多个键值对,这是因为代码中对嵌套对象的处理逻辑有问题。详细来说:
当 root[name] 是一个嵌套对象时,代码没有准确处理嵌套对象的结构,而是直接将其拆开输出。
修正代码:
如果你盼望准确输出嵌套对象的结构,可以修改代码逻辑,递归处理嵌套对象。例如:
void printJsonValue(const Json::Value& value, const std::string& name = "") {
if (value.isObject()) {
for (const auto& key : value.getMemberNames()) {
printJsonValue(value[key], name.empty() ? key : name + "." + key);
}
} else if (value.isArray()) {
for (const auto& item : value) {
printJsonValue(item, name);
}
} else {
std::cout << name << " " << value << std::endl;
}
}
int main() {
Json::Value root;
std::ifstream ifs("profile.json");
Json::CharReaderBuilder builder;
JSONCPP_STRING errs;
if (!parseFromStream(builder, ifs, &root, &errs)) {
std::cout << errs << std::endl;
return EXIT_FAILURE;
}
printJsonValue(root);
return 0;
}
复制代码
修正后的输出:
isbn "123-456-789"
author.lastname "Doe"
author.firstname "Jane"
editor.lastname "Smith"
editor.firstname "Jane"
title "The Ultimate Database Study Guide"
category "Non-Fiction"
category "Technology"
复制代码
总结:
JSON 是无序的,解析后的顺序可能与文件中的顺序不一致。
如果需要保持顺序,可以使用有序的 JSON 库或手动指定顺序。
嵌套对象的处理需要递归遍历,否则会拆开输出。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/)
Powered by Discuz! X3.4