【问题标题】:Iterating through objects in JsonCpp遍历 JsonCpp 中的对象
【发布时间】:2026-01-31 11:30:01
【问题描述】:

我有一个使用 jsoncpp 解码 JSON 字符串的 C++ 应用程序。我创建了以下函数,但它只显示*对象...

如何让它转储整个对象列表?

--功能--

SaveJSON( json_data ); 

bool CDriverConfigurator::PrintJSONTree( Json::Value & root, unsigned short depth /* = 0 */) 
{
    printf( " {type=[%d], size=%d} ", root.type(), root.size() ); 

    if( root.size() > 0 ) {
        for( Json::ValueIterator itr = root.begin() ; itr != root.end() ; itr++ ) {
            PrintJSONTree( itr.key(), depth+1 ); 
        }
        return true;
    }

    // Print depth. 
    for( int tab = 0 ; tab < depth; tab++) {
        printf( "-"); 
    }

    if( root.isString() ) {
        printf( " %s", root.asString().c_str() ); 
    } else if( root.isBool() ) {
        printf( " %d", root.asBool() ); 
    } else if( root.isInt() ) {
        printf( " %d", root.asInt() ); 
    } else if( root.isUInt() ) {
        printf( " %d", root.asUInt() ); 
    } else if( root.isDouble() ) {
        printf( " %f", root.asDouble() ); 
    }
    else 
    {
        printf( " unknown type=[%d]", root.type() ); 
    }


    printf( "\n" ); 
    return true;
}

--- 输入----

{
   "modules":[
      {
         "config":{
            "position":[
               129,
               235
            ]
         },
         "name":"Modbus Task",
         "value":{
            "DeviceID":"This is the name",
            "Function":"01_READ_COIL_STATUS",
            "Length":"99",
            "Scan":"111",
            "Type":"Serve"
         }
      },
      {
         "config":{
            "position":[
               13,
               17
            ]
         },
         "name":"Modbus Connection",
         "value":{
            "Baud":"9600",
            "timeout":"2.5"
         }
      },
      {
         "config":{
            "position":[
               47,
               145
            ]
         },
         "name":"Modbus Device",
         "value":{
            "DeviceID":"55"
         }
      },
      {
         "config":{
            "position":[
               363,
               512
            ]
         },
         "name":"Function Something",
         "value":{

         }
      },
      {
         "config":{
            "position":[
               404,
               701
            ]
         },
         "name":"Function Something",
         "value":{

         }
      }
   ],
   "properties":{
      "Blarrg":"",
      "description":"",
      "name":"Modbus"
   },
   "wires":[
      {
         "src":{
            "moduleId":1,
            "terminal":"modbus.connection.output"
         },
         "tgt":{
            "moduleId":2,
            "terminal":"modbus.connection.input"
         }
      },
      {
         "src":{
            "moduleId":2,
            "terminal":"modbus.device.output"
         },
         "tgt":{
            "moduleId":0,
            "terminal":"modbus.device.output"
         }
      },
      {
         "src":{
            "moduleId":3,
            "terminal":"dataOut"
         },
         "tgt":{
            "moduleId":4,
            "terminal":"dataIn"
         }
      },
      {
         "src":{
            "moduleId":3,
            "terminal":"dataIn"
         },
         "tgt":{
            "moduleId":0,
            "terminal":"data1"
         }
      }
   ]
}

--输出--

{type=[7], size=3} {type=[4], size=0} - modules
{type=[4], size=0} - properties
{type=[4], size=0} - wires 

【问题讨论】:

    标签: c++ json jsoncpp


    【解决方案1】:

    您遇到了一些错误,这些错误与似乎没有很好地处理递归或 JSON 的键->值性质以及这与您正在使用的库的关系有关。我根本没有测试过这段代码,但它应该会更好。

    void CDriverConfigurator::PrintJSONValue( const Json::Value &val )
    {
        if( val.isString() ) {
            printf( "string(%s)", val.asString().c_str() ); 
        } else if( val.isBool() ) {
            printf( "bool(%d)", val.asBool() ); 
        } else if( val.isInt() ) {
            printf( "int(%d)", val.asInt() ); 
        } else if( val.isUInt() ) {
            printf( "uint(%u)", val.asUInt() ); 
        } else if( val.isDouble() ) {
            printf( "double(%f)", val.asDouble() ); 
        }
        else 
        {
            printf( "unknown type=[%d]", val.type() ); 
        }
    }
    
    bool CDriverConfigurator::PrintJSONTree( const Json::Value &root, unsigned short depth /* = 0 */) 
    {
        depth += 1;
        printf( " {type=[%d], size=%d}", root.type(), root.size() ); 
    
        if( root.size() > 0 ) {
            printf("\n");
            for( Json::Value::const_iterator itr = root.begin() ; itr != root.end() ; itr++ ) {
                // Print depth. 
                for( int tab = 0 ; tab < depth; tab++) {
                   printf("-"); 
                }
                printf(" subvalue(");
                PrintJSONValue(itr.key());
                printf(") -");
                PrintJSONTree( *itr, depth); 
            }
            return true;
        } else {
            printf(" ");
            PrintJSONValue(root);
            printf( "\n" ); 
        }
        return true;
    }
    

    【讨论】:

    • 正是我想要的。谢谢。
    • @Steven smethurst:真正有趣的是,我以前从未看过那​​个图书馆。 :-)
    • @cegprakash:为什么要删除“参考”标签?
    • 仅供任何好奇的人参考,可以在这里找到采用 getMemberNames() 路线的方法:en.wikibooks.org/wiki/…
    • @Omnifarious:实际上,Json::ValueIterator 是一个 typedef。还有Json::ValueConstIterator typedef。因此,也许正确的更改是将Json::ValueIterator 替换为Json::ValueConstIterator。 GCC 在错误消息中建议Json::Value::const_iterator,因此很可能这是建议编辑的原因。
    【解决方案2】:

    如果您只是想打印出 Json::Value,可以使用 method

    Json::Value val;
    /*...build the value...*/
    cout << val.toStyledString() << endl;
    

    另外,您可能想查看Json::StyledWriter,它的文档是here。我相信它会打印出人性化的版本。此外,Json::FastWriter、文档here 打印出更紧凑的表格。

    【讨论】:

    • 这会产生我正在寻找的输出,但我正在做这个练习来学习如何遍历 JSON 树。谢谢
    【解决方案3】:

    有一种简单的方法可以遍历 json::value 中的所有字段。我省略了 printf 的东西。

    #include "cpprest/json.h"
    #include "cpprest/filestream.h"
    
    using web::json::value;
    using std::wstring;
    
    static void printOneValue(const wstring &key, const double &value);
    static void printOneValue(const wstring &key, const bool &value);
    static void printOneValue(const wstring &key, const int &value);
    static void printOneValue(const wstring &key, const wstring &value);
    static void printOne(const wstring &key, const value &v, _num level);
    static void printTree(const value &v);
    
    static void printTree(const value &v)
    {
        if(!v.is_object())
            return;
    
        try
        {
            printOne(wstring(), v, 0);
        }
        catch(...)
        {
            // error handling
        }
    }
    
    static void printOne(const wstring &key, const value &v, _num level)
    {
        switch(v.type())
        {
        case value::value_type::Number:
            if(v.is_double())
                printOneValue(key, v.as_double());
            else
                printOneValue(key, v.as_integer());
            break;
        case value::value_type::Boolean:
            printOneValue(key, v.as_bool());
            break;
        case value::value_type::String:
            printOneValue(key, v.as_string());
            break;
        case value::value_type::Object:
            for(auto iter : v.as_object())
            {
                const wstring &k = iter.first;
                const value &val = iter.second;
                printOne(k, val, level+1);
            }
            break;
        case value::value_type::Array:
            for(auto it : v.as_array())
            {
                printOne(key, it, level+1);
            }
            break;
        case value::value_type::Null:
        default:
            break;
        }
    }
    
    static void printOneValue(const wstring &key, const wstring &value)
    {
        // process your key and value
    }
    
    static void printOneValue(const wstring &key, const int &value)
    {
        // process your key and value
    }
    
    static void printOneValue(const wstring &key, const double &value)
    {
        // process your key and value
    }
    
    static void printOneValue(const wstring &key, const bool &value)
    {
        // process your key and value
    }
    

    【讨论】:

    • 虽然此代码可能会回答问题,但提供有关它如何和/或为什么解决问题的额外上下文将提高​​答案的长期价值。请阅读此how-to-answer 以提供高质量的答案。
    • 这里的示例代码甚至不是基于 JsonCpp,而是一个完全不同的库!所以这是一个完全不同的问题的答案。
    【解决方案4】:

    这是一个很好的例子,可以打印json 对象和对象成员(以及它的值):

    Json::Value root;               // Json root
    Json::Reader parser;            // Json parser
    
    // Json content
    string strCarPrices ="{ \"Car Prices\": [{\"Aventador\":\"$393,695\", \"BMW\":\"$40,250\",\"Porsche\":\"$59,000\",\"Koenigsegg Agera\":\"$2.1 Million\"}]}";
    
    // Parse the json
    bool bIsParsed = parser.parse( strCarPrices, root );
    if (bIsParsed == true)
    {
        // Get the values
        const Json::Value values = root["Car Prices"];
    
        // Print the objects
        for ( int i = 0; i < values.size(); i++ )
        {
            // Print the values
            cout << values[i] << endl;
    
            // Print the member names and values individually of an object
            for(int j = 0; j < values[i].getMemberNames().size(); j++)
            {
                // Member name and value
                cout << values[i].getMemberNames()[j] << ": " << values[i][values[i].getMemberNames()[j]].asString() << endl;
            }
        }
    }
    else
    {
        cout << "Cannot parse the json content!" << endl;
    }
    

    输出:

    {
            "Aventador" : "$393,695",
            "BMW" : "$40,250",
            "Koenigsegg Agera" : "$2.1 Million",
            "Porsche" : "$59,000"
    }
    Aventador: $393,695
    BMW: $40,250
    Koenigsegg Agera: $2.1 Million
    Porsche: $59,000
    

    【讨论】:

      【解决方案5】:

      给定成员名称,获取值

      // Print all items under data1 value
      vector<string> memberNames = root["test1"]["data1"].getMemberNames();
      for (const string& mn : memberNames)
      {
          cout << "[" << mn << "]:" << "[" << root["test1"]["data1"].get(mn, "None") << "]" << endl;
      }
      

      【讨论】: