C++ RapidJSON-使用通配符迭代具有不同成员名称的复杂JSON结构

C++ RapidJSON-使用通配符迭代具有不同成员名称的复杂JSON结构,c++,json,rapidjson,C++,Json,Rapidjson,我有一个复杂的JSON要加载到C++11的数据结构中,我得到了关于RapidJSON的高度推荐。我需要迭代一个复杂的JSON,并四处寻找如何实现它的答案。我找到的最好的答案是 但是,将此解决方案与我的解决方案匹配时存在一个小问题,我在JSON中有不同名称但内容相同的成员: "responsibilities": { "starters_reciepe": { "name": "bok choi salad", "type": "veggie", "ingredient

我有一个复杂的JSON要加载到C++11的数据结构中,我得到了关于RapidJSON的高度推荐。我需要迭代一个复杂的JSON,并四处寻找如何实现它的答案。我找到的最好的答案是

但是,将此解决方案与我的解决方案匹配时存在一个小问题,我在JSON中有不同名称但内容相同的成员:

"responsibilities": {
  "starters_reciepe": {
    "name": "bok choi salad",
    "type": "veggie",
    "ingredients": {
      "leafyIng": "bok choi",
      "proteinIng": "tofu",
      "seasoning": [
        {
          "2 tsp": "salt",
          "1 tsp": "turmric"
        }
      ]
    }
  },
  "mainCourse_reciepe": {
    "name": "pad tai",
    "type": "yum yum",
    "ingredients": {
      "leafyIng": "chard",
      "proteinIng": "soylent green"
      "seasoning": [
        {
          "2 tsp": "black pepper",
          "1 tsp": "tears of the angels"
        }
      ]
    }
}
}

基本上,我需要检查一下配料的内容,但我不能忘记一个事实,即开胃菜和主菜不同

编辑: 这是我的密码:

Document d;

ifstream in("TestingJSON.json", ios::binary);
if (!in)
    throw runtime_error("Failed to open file");

istreambuf_iterator<char> head(in);
istreambuf_iterator<char> tail;
string data(head, tail);

d.Parse(data.c_str());

const Value& prog = d["responsibilities"];
for (Value::ConstValueIterator p = prog.Begin(); p != prog.End(); ++p) {
cout << (*p)["iUniqueID"].GetString()<<endl;
    const Value& inFiles = (*p)["inFiles"];
    for (Value::ConstValueIterator inFile = inFiles.Begin(); inFile != prog.End(); ++inFile) {
        cout << (*inFile)["sFileType"].GetString() << endl;
        cout << (*inFile)["pos"]["x1"].GetInt() << endl;
    }
}
文件d;
ifstream-in(“TestingJSON.json”,ios::binary);
如果(!in)
抛出运行时_错误(“打开文件失败”);
istreambuf_迭代器头(in);
istreambuf_迭代器尾部;
字符串数据(头、尾);
d、 解析(data.c_str());
const Value&prog=d[“责任”];
对于(Value::ConstValueIterator p=prog.Begin();p!=prog.End();++p){

cout如果您只需要检查字符串是否以已知值结尾,那么直接比较字符串非常简单,无需使用通配符库:

auto& obj = doc["responsibilities"];
std::string suffix = "_reciepe";
for (auto p = obj.MemberBegin(); p != obj.MemberEnd(); ++p) {
    auto& member_name = p->name;
    if (member_name.GetStringLength() >= suffix.length()) {
        if (memcmp(member_name.GetString() + member_name.GetStringLength() - suffix.length(), suffix.c_str(), suffix.length()) == 0) {
            // Process matching node
            std::cout << p->value["name"].GetString() << std::endl;
        }
    }
}
auto&obj=doc[“职责”];
std::string suffix=“_receipe”;
对于(auto p=obj.MemberBegin();p!=obj.MemberEnd();++p){
自动&member\u name=p->name;
if(member_name.GetStringLength()>=后缀.length()){
if(memcmp(member_name.GetString()+member_name.GetStringLength()-后缀.length(),后缀.c_str(),后缀.length())==0){
//进程匹配节点

std::cout value[“name”]。GetString()始终使用linter(例如)验证原始JSON。您问题中的此JSON无效。您需要修复此问题

JSON中的
“responsibilites”
对象仅包含配方。我不确定为什么需要将其与
*\u配方进行比较。但是,考虑到下面的示例,如果需要,您可以轻松实现该比较。这在这方面可能会有所帮助


在这些迭代中,您可以使用C++11的基于范围的for循环。只需根据您的用例处理您要使用/操作的正确类型。如果有疑问,请参阅rapidjson和文档

下面是一个以原始文字字符串作为JSON输入的示例:

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

int main()
{
    constexpr auto data = R"json(
    {
      "responsibilities": {
          "starters_recipe": {
              "name": "bok choi salad",
              "type": "veggie",
              "ingredients": {
                  "leafyIng": "bok choi",
                  "proteinIng": "tofu",
                  "seasoning": [{
                      "2 tsp": "salt",
                      "1 tsp": "turmric"
                  }]
              }
          },
          "mainCourse_recipe": {
              "name": "pad tai",
              "type": "yum yum",
              "ingredients": {
                  "leafyIng": "chard",
                  "proteinIng": "soylent green",
                  "seasoning": [{
                      "2 tsp": "black pepper",
                      "1 tsp": "tears of the angels"
                  }]
              }
          }
      }
    }
    )json";

    rapidjson::Document doc;
    doc.Parse( data );

    const auto& courses = doc["responsibilities"].GetObject();
    for ( const auto& course : courses )
    {
        const auto& course_name = course.name.GetString();
        const auto& recipe      = courses[course_name].GetObject();
        const auto& recipe_name = recipe["name"].GetString();
        const auto& ingredients = recipe["ingredients"].GetObject();
        const auto& leafyIng    = ingredients["leafyIng"].GetString();
        const auto& proteinIng  = ingredients["proteinIng"].GetString();
        const auto& seasoning   = ingredients["seasoning"].GetArray()[0].GetObject();

        std::cout << "Course: " << course_name << '\n'
                  << "Recipe: " << recipe_name << '\n'
                  << "Ingredients:\n"
                  << "- Leaf     : " << leafyIng << '\n'
                  << "- Protein  : " << proteinIng << '\n'
                  << "- Seasoning:\n";

        for ( const auto& s : seasoning )
        {
            const auto& k = s.name.GetString();
            const auto& v = s.value.GetString();
            std::cout << "  - " << k << ", " << v << '\n';
        }

        std::cout << '\n';
    }

    return 0;
}

“调味”
数组只包含一个对象,这就是此行引用第0个索引的原因:

const auto& seasoning = ingredients["seasoning"].GetArray()[0].GetObject();
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^
我猜您想要的是一个对象数组,而不是一个包含单个对象的数组

这:

而不是这个:

"seasoning": [{    
      "2 tsp": "black pepper",
      "1 tsp": "tears of the angels"
}]

您还必须在代码中相应地处理它。

看起来不错,但我尝试运行它,结果是:断言失败:IsObject(),文件c:\testingcode\rapidjson\document.h,第1285行testingcode.exe(进程90364)以代码3退出。我编辑了原始帖子并添加了我的代码。您发布的JSON无效。请使用在线linter进行检查,例如……并且,您发布的代码是您上面发布的代码的副本。它与您发布的JSON无关。您需要使用正确的代码更新正确的JSON。
"seasoning": [   
     { "2 tsp": "black pepper" },
     {  "1 tsp": "tears of the angels" }
]
"seasoning": [{    
      "2 tsp": "black pepper",
      "1 tsp": "tears of the angels"
}]