C++中基于RapidJSON的JSON比较功能实现遇阻,求技术帮助
解决RapidJSON实现JSON比较的问题
嘿,我明白你在实现JSON比较功能时卡在Document d3这块儿了——咱们一步步拆解问题,把这个功能补全。首先,JSON比较的核心是递归遍历两个JSON的所有节点,逐个对比类型和值;而你提到的d3,推测应该是用来记录差异结果的(如果只是判断是否相等,其实它不是必须的,但如果要生成差异报告就很有用)。
完整实现代码
先给你补全test类的代码,包含递归对比的核心逻辑和d3的初始化/差异记录思路:
#include <iostream> #include <string> #include <cstring> #include <algorithm> #include "include/rapidjson/document.h" #include "include/rapidjson/writer.h" #include "include/rapidjson/prettywriter.h" #include "include/rapidjson/stringbuffer.h" using namespace std; using namespace rapidjson; class test { private: // 辅助递归函数:对比两个Value节点,同时记录差异到diffDoc static bool isEqualValue(const Value& v1, const Value& v2, string& tempPath, Document& diffDoc) { // 先检查类型是否一致 if (v1.GetType() != v2.GetType()) { // 记录类型差异到diffDoc Value pathVal(tempPath.c_str(), diffDoc.GetAllocator()); Value diffObj(kObjectType); diffObj.AddMember("type_mismatch", true, diffDoc.GetAllocator()); diffObj.AddMember("expected_type", v2.GetType(), diffDoc.GetAllocator()); diffObj.AddMember("actual_type", v1.GetType(), diffDoc.GetAllocator()); diffDoc.AddMember(pathVal, diffObj, diffDoc.GetAllocator()); cout << "Type mismatch at path: " << tempPath << endl; return false; } switch (v1.GetType()) { case kObjectType: { // 对比对象成员数量 if (v1.MemberCount() != v2.MemberCount()) { Value pathVal(tempPath.c_str(), diffDoc.GetAllocator()); Value diffObj(kObjectType); diffObj.AddMember("member_count_mismatch", true, diffDoc.GetAllocator()); diffObj.AddMember("expected_count", v2.MemberCount(), diffDoc.GetAllocator()); diffObj.AddMember("actual_count", v1.MemberCount(), diffDoc.GetAllocator()); diffDoc.AddMember(pathVal, diffObj, diffDoc.GetAllocator()); cout << "Member count mismatch at path: " << tempPath << endl; return false; } // 遍历所有成员 for (auto it1 = v1.MemberBegin(); it1 != v1.MemberEnd(); ++it1) { string key = it1->name.GetString(); auto it2 = v2.FindMember(key.c_str()); if (it2 == v2.MemberEnd()) { Value pathVal((tempPath.empty() ? key : tempPath + "." + key).c_str(), diffDoc.GetAllocator()); Value diffObj(kObjectType); diffObj.AddMember("missing_member", true, diffDoc.GetAllocator()); diffDoc.AddMember(pathVal, diffObj, diffDoc.GetAllocator()); cout << "Missing member: " << tempPath << "." << key << endl; return false; } string newPath = tempPath.empty() ? key : tempPath + "." + key; if (!isEqualValue(it1->value, it2->value, newPath, diffDoc)) { return false; } } return true; } case kArrayType: { // 对比数组长度 if (v1.Size() != v2.Size()) { Value pathVal(tempPath.c_str(), diffDoc.GetAllocator()); Value diffObj(kObjectType); diffObj.AddMember("array_size_mismatch", true, diffDoc.GetAllocator()); diffObj.AddMember("expected_size", v2.Size(), diffDoc.GetAllocator()); diffObj.AddMember("actual_size", v1.Size(), diffDoc.GetAllocator()); diffDoc.AddMember(pathVal, diffObj, diffDoc.GetAllocator()); cout << "Array size mismatch at path: " << tempPath << endl; return false; } // 遍历数组元素 for (SizeType i = 0; i < v1.Size(); ++i) { string newPath = tempPath.empty() ? "[" + to_string(i) + "]" : tempPath + "[" + to_string(i) + "]"; if (!isEqualValue(v1[i], v2[i], newPath, diffDoc)) { return false; } } return true; } case kStringType: { if (strcmp(v1.GetString(), v2.GetString()) != 0) { Value pathVal(tempPath.c_str(), diffDoc.GetAllocator()); Value diffObj(kObjectType); diffObj.AddMember("string_mismatch", true, diffDoc.GetAllocator()); diffObj.AddMember("expected", v2.GetString(), diffDoc.GetAllocator()); diffObj.AddMember("actual", v1.GetString(), diffDoc.GetAllocator()); diffDoc.AddMember(pathVal, diffObj, diffDoc.GetAllocator()); cout << "String mismatch at path: " << tempPath << endl; return false; } return true; } case kNumberType: { bool isEqual = false; if (v1.IsInt() && v2.IsInt()) { isEqual = (v1.GetInt() == v2.GetInt()); } else if (v1.IsDouble() && v2.IsDouble()) { isEqual = (v1.GetDouble() == v2.GetDouble()); } else if (v1.IsUint() && v2.IsUint()) { isEqual = (v1.GetUint() == v2.GetUint()); } if (!isEqual) { Value pathVal(tempPath.c_str(), diffDoc.GetAllocator()); Value diffObj(kObjectType); diffObj.AddMember("number_mismatch", true, diffDoc.GetAllocator()); // 简化处理:把数字转成字符串存储 char buf[64]; sprintf(buf, "%g", v2.IsInt() ? (double)v2.GetInt() : v2.GetDouble()); diffObj.AddMember("expected", buf, diffDoc.GetAllocator()); sprintf(buf, "%g", v1.IsInt() ? (double)v1.GetInt() : v1.GetDouble()); diffObj.AddMember("actual", buf, diffDoc.GetAllocator()); diffDoc.AddMember(pathVal, diffObj, diffDoc.GetAllocator()); cout << "Number mismatch at path: " << tempPath << endl; return false; } return true; } case kBoolType: { if (v1.GetBool() != v2.GetBool()) { Value pathVal(tempPath.c_str(), diffDoc.GetAllocator()); Value diffObj(kObjectType); diffObj.AddMember("bool_mismatch", true, diffDoc.GetAllocator()); diffObj.AddMember("expected", v2.GetBool(), diffDoc.GetAllocator()); diffObj.AddMember("actual", v1.GetBool(), diffDoc.GetAllocator()); diffDoc.AddMember(pathVal, diffObj, diffDoc.GetAllocator()); cout << "Bool mismatch at path: " << tempPath << endl; return false; } return true; } case kNullType: { return true; } default: cout << "Unsupported JSON type at path: " << tempPath << endl; return false; } } public: static bool isEqual(const string &item1, const string &item2, const string &temp) { // 解析第一个JSON,检查解析错误 Document d1; if (d1.Parse(item1.c_str()).HasParseError()) { cout << "Failed to parse first JSON: error code " << d1.GetParseError() << " at offset " << d1.GetErrorOffset() << endl; return false; } // 解析第二个JSON,检查解析错误 Document d2; if (d2.Parse(item2.c_str()).HasParseError()) { cout << "Failed to parse second JSON: error code " << d2.GetParseError() << " at offset " << d2.GetErrorOffset() << endl; return false; } // 初始化d3为差异结果文档 Document d3; d3.SetObject(); string path = temp.empty() ? "" : temp; // 调用递归对比函数,同时把差异写入d3 bool isEqual = isEqualValue(d1, d2, path, d3); // 如果存在差异,格式化输出d3的内容 if (!isEqual) { StringBuffer buffer; PrettyWriter<StringBuffer> writer(buffer); d3.Accept(writer); cout << "\n差异详情:\n" << buffer.GetString() << endl; } return isEqual; } }; // 测试用例 int main() { string json1 = R"({"name":"Alice","age":30,"hobbies":["reading","hiking"],"active":true})"; string json2 = R"({"name":"Alice","age":30,"hobbies":["reading","hiking"],"active":true})"; string json3 = R"({"name":"Bob","age":25,"hobbies":["gaming"],"active":false})"; cout << "=== 对比json1和json2 ===" << endl; bool result1 = test::isEqual(json1, json2, ""); cout << "结果: " << boolalpha << result1 << "\n" << endl; cout << "=== 对比json1和json3 ===" << endl; bool result2 = test::isEqual(json1, json3, ""); cout << "结果: " << boolalpha << result2 << endl; return 0; }
关键部分解释
- 解析错误检查:原代码缺少JSON解析失败的处理,这里添加了
HasParseError()的判断,能快速定位输入JSON的格式问题。 - 递归对比逻辑:
isEqualValue函数是核心,它会根据JSON节点的类型(对象、数组、字符串等)做针对性对比,确保每个嵌套节点都能被覆盖。 - d3的作用:这里把
d3作为差异结果文档,每当发现两个JSON节点不相等时,就把差异信息(路径、类型/值差异)写入d3,最后可以用PrettyWriter格式化输出差异详情。 - 路径追踪:通过
tempPath参数记录当前对比的节点路径,方便快速定位差异位置。
运行效果
测试用例中,对比json1和json2会返回true,对比json1和json3会返回false,同时输出详细的差异路径和信息,比如缺少的成员、值不匹配的节点等。
内容的提问来源于stack exchange,提问作者Bishal Sahoo
相关产品推荐
相关产品推荐

