【问题标题】:Is there an elegant way to cascade-merge two JSON trees using jsoncpp?有没有一种优雅的方法可以使用 jsoncpp 级联合并两个 JSON 树?
【发布时间】:2014-04-26 02:02:30
【问题描述】:

我正在使用 jsoncpp 从 JSON 文件中读取设置。

我想要两个级联设置文件,例如 MasterSettings.jsonLocalSettings.json,其中 LocalSettings 是 MasterSettings 的子集。我想先加载 MasterSettings,然后再加载 LocalSettings。如果 LocalSettings 的值与 MasterSettings 不同,则该值将覆盖 MasterSettings 中的值。很像 CSS 中的级联。

有没有什么优雅的方法可以用 jsoncpp 做到这一点?

【问题讨论】:

    标签: c++ json jsoncpp


    【解决方案1】:

    我将假设您的设置文件是 JSON 对象。

    正如here 所见,当 JSONCpp 解析文件时,它会清除根节点的内容。这意味着尝试在旧文件之上解析新文件不会保留旧数据。但是,如果您将两个文件解析为单独的 Json::Value 节点,则可以直接通过使用 getMemberNames 迭代第二个对象中的键来自己递归复制值。

    // Recursively copy the values of b into a. Both a and b must be objects.
    void update(Json::Value& a, Json::Value& b) {
        if (!a.isObject() || !b.isObject()) return;
    
        for (const auto& key : b.getMemberNames()) {
            if (a[key].isObject()) {
                update(a[key], b[key]);
            } else {
                a[key] = b[key];
            }
        }
    }
    

    【讨论】:

    • 对于a 中不存在的键,这将在if(a[key].isObject()) { 上失败。引用不存在的键将其实例化为nullValue,并且 isObject() 在 nullValue 上返回 true。这样,您将在 a=null 上递归调用更新,并且不会发生复制。 (另外,对象类型a[key] 不会被非对象b[key] 覆盖。)您需要做的是if(a[key].type() == Json::objectValue && b[key].type() == Json::objectValue) { - 然后才执行递归合并,否则只需覆盖a[key] 值。
    • 在 Qt5 中将变量类型更改为 QJson 似乎可行。
    • 不能将b[key]移动到a[key]吗?
    【解决方案2】:

    我知道已经有一段时间了。但是……

    除了正确答案和注释之外,这里有一个代码版本,供使用旧g++版本的人使用:

    void jsonMerge(Json::Value &a, Json::Value &b) {                                                                        
                                                                                                                      
       if (!a.isObject() || !b.isObject()) return;                                                                           
                                                                                                                        
       vector<string> member_name = b.getMemberNames();                                                                      
       string key = "";                                                                                                      
       for (unsigned i = 0, len = member_name.size(); i < len; i++) {                                                        
           key = member_name[i];                                                                                               
                                                                                                                        
           if (!a[key].isNull() && a[key].type() == Json::objectValue && b[key].type() == Json::objectValue) {                 
               jsonMerge(a[key], b[key]);                                                                                        
           } else {                                                                                                            
               a[key] = b[key];                                                                                                  
           }                                                                                                                   
       }                                                                                                                     
       member_name.clear();                                                                                                  
    }
    

    【讨论】:

      猜你喜欢
      • 2010-12-10
      • 1970-01-01
      • 1970-01-01
      • 2010-12-20
      • 2013-04-16
      • 2021-08-14
      • 1970-01-01
      • 2015-07-30
      • 2021-12-19
      相关资源
      最近更新 更多