如何使用rapidjson合并两个json文件

时间:2016-10-13 05:59:39

标签: c++ json rapidjson

我正在尝试通过加载两个json文件来构建Document。最后加载的文件具有最高优先级。 在下面的示例中,来自item1.value1的{​​{1}}会覆盖file B的值。 file A中不存在item1.value2 item2,因此最终文档仅从file A获取值 文件A:

file B

文件B:

{
level1: {
      level2: {
               item1: {
                       value1: 20,
                      }
              }
}

我的目标:

{
   level1: {
         item2{
               value1: 50
               value2: 60,        
               }
       level2: {
            item1:{
                       value1: 40
                       value2: 30,
       }
  }
}

当我使用范围迭代文档时,另一个问题是迭代{ level1: { item2{ value1: 50 value2: 60, } level2: { item1: { value1: 40, value2: 30, } } } 成员,我怎样才能浏览整个DOM?

level1

2 个答案:

答案 0 :(得分:0)

我想你会尝试这个(适合我):

void mergeObjects(rapidjson::Value &dstObject, rapidjson::Value &srcObject, rapidjson::Document::AllocatorType &allocator)
{
    for (auto srcIt = srcObject.MemberBegin(); srcIt != srcObject.MemberEnd(); ++srcIt)
    {
        auto dstIt = dstObject.FindMember(srcIt->name);
        if (dstIt != dstObject.MemberEnd())
        {
            assert(srcIt->value.GetType() == dstIt->value.GetType());
            if (srcIt->value.IsArray())
            {
                for (auto arrayIt = srcIt->value.Begin(); arrayIt != srcIt->value.End(); ++arrayIt)
                {
                    dstIt->value.PushBack(*arrayIt, allocator);
                }
            }
            else if (srcIt->value.IsObject())
            {
                mergeObjects(dstIt->value, srcIt->value, allocator);
            }
            else
            {
                dstIt->value = srcIt->value;
            }
        }
        else
        {
            dstObject.AddMember(srcIt->name, srcIt->value, allocator);
        }
    }
}
//...
rapidjson::Document from;
rapidjson::Document to;
mergeObjects(to, from, to.GetAllocator());

注意,节点类型必须相同。它还通过连接而不是替换来合并数组。

您可以使用递归迭代整个DOM模型(如上所述)。

希望它有所帮助。

答案 1 :(得分:0)

以上实现假定srcObjectdstObject共享相同的内存,因为它传递原始值而不是复制原始值。 这意味着dstObject将在释放srcObject时保留释放的对象。

我通过复制值来实现它:

bool mergeObjects(rapidjson::Value &dstObject, rapidjson::Value &srcObject, rapidjson::Document::AllocatorType &allocator)
{
    for (auto srcIt = srcObject.MemberBegin(); srcIt != srcObject.MemberEnd(); ++srcIt)
    {
        auto dstIt = dstObject.FindMember(srcIt->name);
        if (dstIt == dstObject.MemberEnd())
        {
            rapidjson::Value dstName ;
            dstName.CopyFrom(srcIt->name, allocator);
            rapidjson::Value dstVal ;
            dstVal.CopyFrom(srcIt->value, allocator) ;

            dstObject.AddMember(dstName, dstVal, allocator);

            dstName.CopyFrom(srcIt->name, allocator);
            dstIt = dstObject.FindMember(dstName);
            if (dstIt == dstObject.MemberEnd())
                return false ;
        }
        else
        {
            auto srcT = srcIt->value.GetType() ;
            auto dstT = dstIt->value.GetType() ;
            if(srcT != dstT)
                return false ;

            if (srcIt->value.IsArray())
            {
                for (auto arrayIt = srcIt->value.Begin(); arrayIt != srcIt->value.End(); ++arrayIt)
                {
                    rapidjson::Value dstVal ;
                    dstVal.CopyFrom(*arrayIt, allocator) ;
                    dstIt->value.PushBack(dstVal, allocator);
                }
            }
            else if (srcIt->value.IsObject())
            {
                if(!mergeObjects(dstIt->value, srcIt->value, allocator))
                    return false ;
            }
            else
            {
                dstIt->value.CopyFrom(srcIt->value, allocator) ;
            }
        }
    }

    return true ;
}