You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过递归使用Property Tree/RapidJSON解析深层嵌套JSON并实现JSON比较?

递归解析深层嵌套JSON + equalJson代码逻辑分析

一、递归解析深层嵌套JSON的实现

JSON本身就是天然的树形结构,递归是处理这种深层嵌套最直观的方式——跟着层级往下钻,遇到分支(对象/数组)就递归处理,遇到叶子(基本类型)就直接处理。下面分别用Boost.Property Tree和RapidJSON来实现:

1. 用Boost.Property Tree实现递归解析

Boost.Property Tree(简称PTree)会把JSON解析成树状的ptree对象,我们只需要遍历每个节点,遇到子树就递归调用自己:

#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <iostream>

void parseNestedPTree(const boost::property_tree::ptree& tree, int depth = 0) {
    // 用缩进体现层级,看起来更清晰
    std::string indent(depth * 2, ' ');
    
    for (const auto& pair : tree) {
        const std::string& key = pair.first;
        const boost::property_tree::ptree& node = pair.second;
        
        // 如果是叶子节点(没有子节点),直接输出键值
        if (node.empty()) {
            std::cout << indent << key << ": " << node.get_value<std::string>() << std::endl;
        } else {
            // 非叶子节点,先打印键名,再递归解析子树
            std::cout << indent << key << ": {" << std::endl;
            parseNestedPTree(node, depth + 1);
            std::cout << indent << "}" << std::endl;
        }
    }
}

int main() {
    boost::property_tree::ptree root;
    boost::property_tree::read_json("nested_data.json", root);
    parseNestedPTree(root);
    return 0;
}

2. 用RapidJSON实现递归解析

RapidJSON的Value类型区分了JSON的所有数据类型,递归时需要先判断当前值的类型,再做对应处理:

#include "rapidjson/document.h"
#include <iostream>

using namespace rapidjson;

void parseNestedRapidJSON(const Value& value, int depth = 0) {
    std::string indent(depth * 2, ' ');
    
    switch (value.GetType()) {
        case kObjectType: {
            // 对象类型:遍历所有成员,递归处理每个成员的值
            for (Value::ConstMemberIterator itr = value.MemberBegin(); itr != value.MemberEnd(); ++itr) {
                std::cout << indent << itr->name.GetString() << ": ";
                parseNestedRapidJSON(itr->value, depth + 1);
                std::cout << std::endl;
            }
            break;
        }
        case kArrayType: {
            // 数组类型:遍历所有元素,递归处理每个元素
            std::cout << indent << "[" << std::endl;
            for (Value::ConstValueIterator itr = value.Begin(); itr != value.End(); ++itr) {
                parseNestedRapidJSON(*itr, depth + 1);
                std::cout << std::endl;
            }
            std::cout << indent << "]";
            break;
        }
        // 处理基本类型:直接输出值
        case kStringType: std::cout << value.GetString(); break;
        case kNumberType: std::cout << value.GetDouble(); break;
        case kTrueType: std::cout << "true"; break;
        case kFalseType: std::cout << "false"; break;
        case kNullType: std::cout << "null"; break;
        default: std::cout << "unknown type";
    }
}

int main() {
    const char* json_str = R"({"user":"Bob","profile":{"age":30,"tags":["programmer","hiker"]}})";
    Document doc;
    doc.Parse(json_str);
    parseNestedRapidJSON(doc);
    return 0;
}

核心逻辑就是类型判断+递归:遇到对象/数组就深入下一层,基本类型直接输出,完美贴合JSON的嵌套结构。

二、equalJson函数代码逻辑分析

先把你给出的代码片段补全(结合上下文推测完整逻辑):

static bool equalJson(Value &json1, Value &json2, Value &reference, bool a) { 
    for (Value::ConstMemberIterator itr = reference.MemberBegin(); itr <= reference.MemberEnd(); itr++) { 
        if (itr->value.GetType() == kArrayType) { 
            for (auto itr1 = itr->value.Begin(); itr1 != itr->value.End(); itr1++) { 
                // cout<<itr->name.GetString()<<endl;//获取顶层为数组的键或成员 
                switch (itr1->GetType()) { 
                    case kObjectType: 
                        // 遍历数组中的对象成员,递归校验
                        for (auto sub_itr = itr1->MemberBegin(); sub_itr != itr1->MemberEnd(); ++sub_itr) {
                            if (!equalJson(json1[sub_itr->name.GetString()], json2[sub_itr->name.GetString()], *sub_itr, a)) {
                                return false;
                            }
                        }
                        break;
                    // 其他数组元素类型的处理逻辑(比如字符串、数字)
                }
            }
        }
        // 其他reference成员类型的处理逻辑(比如单个对象、基本类型)
    }
    // 所有指定字段都匹配则返回true
    return true;
}

核心设计意图

这个函数不是完全比较两个JSON的所有内容,而是基于reference的模板,校验json1和json2在指定字段和层级上是否匹配——相当于只关心reference里定义的部分,其他字段不管。

逐段逻辑拆解

  1. 参数说明:

    • json1/json2:需要校验的两个JSON对象
    • reference:校验模板,定义了需要检查的字段、结构
    • bool a:推测是个控制开关(比如是否严格匹配空值、是否忽略类型差异),具体要看完整实现
  2. 遍历reference的顶层成员:

    for (Value::ConstMemberIterator itr = reference.MemberBegin(); itr <= reference.MemberEnd(); itr++)
    

    ❗这里有个潜在bug:RapidJSON的MemberEnd()是尾后迭代器,正确的遍历判断应该是itr != reference.MemberEnd(),用<=会导致越界访问。

  3. 处理reference中的数组成员:
    如果reference的某个成员是数组,就遍历数组里的每个元素,再根据元素类型做处理。

  4. 递归处理数组中的对象元素:
    当数组元素是对象时,遍历这个对象的所有成员,递归调用equalJson,深入到下一层校验json1和json2对应的字段——只要有一个字段不匹配,就直接返回false。
    ❗原代码里内层循环用了和外层一样的变量名itr,这会覆盖外层迭代器,属于明显的代码bug,我改成了sub_itr。

整体流程总结

函数通过递归遍历reference的结构,逐层校验json1和json2在对应位置的内容:

  • 遇到对象/数组就递归深入下一层
  • 一旦发现指定字段不匹配,立即返回false
  • 所有指定字段都匹配则返回true

内容的提问来源于stack exchange,提问作者Pheonix

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:42:56