c++ nlohmann json -如何搜索/查找嵌套对象

lawou6xi  于 2023-11-19  发布在  其他
关注(0)|答案(3)|浏览(152)

我正在尝试使用nlohmann::json覆盖嵌套的json。我的json对象如下:

{
    "one": 1,
    "two": 2
    "three": {
        "three.one": 3.1
    },
}

字符串
我正在尝试遍历和/或查找嵌套对象。但是,似乎没有默认支持。看起来我必须通过创建另一个循环来遍历每个子对象,或者递归地为每个子对象调用fn。
我下面的代码片段及其结果表明,只有顶层迭代才是可能的。

void findNPrintKey (json src, const std::string& key) {
  auto result = src.find(key);
  if (result != src.end()) {
    std::cout << "Entry found for : " << result.key() << std::endl;
  } else {
    std::cout << "Entry not found for : " << key << std::endl ;
  }
}

void enumerate () {

  json j = json::parse("{  \"one\" : 1 ,  \"two\" : 2, \"three\" : { \"three.one\" : 3.1 } } ");
  //std::cout << j.dump(4) << std::endl;

  // Enumerate all keys (including sub-keys -- not working)
  for (auto it=j.begin(); it!=j.end(); it++) {
    std::cout << "key: " << it.key() << " : " << it.value() << std::endl;
  }

  // find a top-level key
  findNPrintKey(j, "one");
  // find a nested key
  findNPrintKey(j, "three.one");
}

int main(int argc, char** argv) {
  enumerate();
  return 0;
}


和输出:

ravindrnathsMBP:utils ravindranath$ ./a.out 
key: one : 1
key: three : {"three.one":3.1}
key: two : 2
Entry found for : one
Entry not found for : three.one


那么,是否有递归迭代可用,或者我们必须使用is_object()方法自己做这件事?

gtlvzcf8

gtlvzcf81#

事实上,迭代并不递归,而且(目前)还没有库函数来实现这一点。

#include "json.hpp"
#include <iostream>

using json = nlohmann::json;

template<class UnaryFunction>
void recursive_iterate(const json& j, UnaryFunction f)
{
    for(auto it = j.begin(); it != j.end(); ++it)
    {
        if (it->is_structured())
        {
            recursive_iterate(*it, f);
        }
        else
        {
            f(it);
        }
    }
}

int main()
{
    json j = {{"one", 1}, {"two", 2}, {"three", {"three.one", 3.1}}};
    recursive_iterate(j, [](json::const_iterator it){
        std::cout << *it << std::endl;
    });
}

字符串
输出为:

1
"three.one"
3.1
2

mbyulnm0

mbyulnm02#

这是从接受的答案中衍生出来的,它给你带来了额外的好处,当你“遍历”json树时,你可以拥有父键(除了迭代器之外)。
父键以列表格式提供,以便轻松地直接覆盖它们。我还提供了将该字符串列表转换为“嵌套json键”(即json_pointer)的方法。这是一个对象,您可以在执行nlohmann::json中内置的各种操作时直接访问k/v对。

实用函数

#include <string>
#include <list>

#include "nlohmann.hpp"

using JsonIter = nlohmann::json::const_iterator;

typedef std::list<std::string> JsonKeys;

std::string toJsonStringKey( const JsonKeys &keys )
{
    static const std::string JSON_KEY_DELIM( "/" );
    std::string s;
    for( auto k : keys ) s.append( JSON_KEY_DELIM + k );
    return s;
}

nlohmann::json::json_pointer toJsonPointerKey( const JsonKeys &keys )
{ return nlohmann::json::json_pointer( toJsonStringKey( keys ) ); }

nlohmann::json::json_pointer toJsonPointerKey(
    const JsonKeys &parentKeys, JsonIter it )
{
    JsonKeys allKeys( parentKeys );
    allKeys.push_back( it.key() );
    return nlohmann::json::json_pointer( toJsonStringKey( allKeys ) );
}

typedef std::function< void( const JsonKeys &parentKeys,
    nlohmann::json::const_iterator it )> WalkJsonCallBack;
void walkJson( const nlohmann::json &jsonObj, JsonKeys &parentKeys,
    WalkJsonCallBack callback )
{
    for( auto it( jsonObj.begin() ); it != jsonObj.end(); ++it )
    {
        if( it->is_structured() )
        {
            parentKeys.push_back( it.key() );
            walkJson( *it, parentKeys, callback );
            parentKeys.pop_back();
        }
        else callback( parentKeys, it );
    }
}

字符串

示例实现

const nlohmann::json parsed( nlohmann::json::parse( raw ) ); 
JsonKeys parentKeys;
walkJson( parsed, parentKeys, []( const JsonKeys &parentKeys, JsonIter it )
{
    // INSERT YOUR CODE HERE

    // Example of getting a pointer key..
    const auto key( toJsonPointerKey( parentKeys, it ) );
    // Now, do whatever with that key...

});

示例数据

这里是OP的示例数据,在添加了一些字段和嵌套之后:

const std::string testData(
    "{  \"one\" : 1 , \"two\" : 2, "
       "\"three\" : { "
        " \"three.one\" : 3.1, "
        " \"three.two\" : { \"three.two.one\" : 3.21, \"three.two.two\" : 3.22 }, "
        " \"three.three\": { \"three.three.one\" : 3.31, \"three.three.two\" : 3.32 }, "
        " \"three.four\": 3.4, "
        " \"three.five\": { \"three.five.one\" : 3.51, \"three.five.two\" : 3.52 } "
        "}, "
        "\"four\" : 4"
    "} " );

lhcgjxsq

lhcgjxsq3#

根据以前的答案,这是测试:

typedef std::list<std::string> json_keys;
typedef std::function< void(const json_keys& key, const json& it)> json_recursive_iterate_callback;

void json_recursive_iterate(const json& js, json_keys& keys, json_recursive_iterate_callback cb)
{
    for (auto& [key, val] : js.items())
    {
        keys.push_back(key);

        if (val.is_structured())
            json_recursive_iterate(val, keys, cb);          
        else
            cb(keys, val);          

        keys.pop_back();
    }
}

字符串
使用方法如下:

json_keys keys;
json_recursive_iterate(body, keys, [&](const json_keys& keys, const json& it)
{               
    std::string key;            
    for (auto k : keys) key.append("/" + k);

    std::cout << key << " = " << it << std::endl;
});

相关问题