Rapid JSON - использование подстановочных знаков для перебора сложных JSON структур с разными именами членов - PullRequest
0 голосов
/ 13 февраля 2020

У меня есть комплекс JSON для загрузки в структуру данных в C ++ 11, и я получил высокие рекомендации по Rapid JSON. Мне нужно перебрать комплекс 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"
        }
      ]
    }
}

}

По сути, мне нужно go над содержимым ингредиентов, но я не могу смириться с тем фактом, что starters_reciepe не похож на mainCourse_reciepe.

РЕДАКТИРОВАНИЕ: Вот мой код:

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;
    }
}

Могу ли я использовать подстановочные знаки и писать * _reciepe?

Я могу найти что-нибудь на Rapid JSON и подстановочные знаки. Это вообще возможно?

Ответы [ 2 ]

1 голос
/ 14 февраля 2020

Всегда проверяйте свои необработанные JSON с помощью линтеров (например, https://jsonlint.com/). Этот JSON в вашем вопросе не действителен. Вам нужно это исправить.

Объект "responsibilites" в вашем JSON содержит только рецепты. Я не уверен, почему вам нужно сравнить его с *_recipe. Но, учитывая приведенный ниже пример, вы можете легко реализовать это сравнение, если это необходимо. Этот поток может быть полезен в этом отношении.


Вы можете использовать диапазон C ++ 11 для l oop для этих итераций. Просто позаботьтесь о правильном типе, который вы хотите использовать / манипулировать в соответствии с вашим вариантом использования. В случае сомнений обратитесь к быстрому json учебному пособию и документации.

Вот пример с необработанной литеральной строкой в ​​качестве JSON input:

#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;
}

Output :

Course: starters_recipe
Recipe: bok choi salad
Ingredients:
- Leaf     : bok choi
- Protein  : tofu
- Seasoning:
  - 2 tsp, salt
  - 1 tsp, turmric

Course: mainCourse_recipe
Recipe: pad tai
Ingredients:
- Leaf     : chard
- Protein  : soylent green
- Seasoning:
  - 2 tsp, black pepper
  - 1 tsp, tears of the angels

Массив "seasoning" содержит только один объект, поэтому эта строка ссылается на 0-й индекс:

const auto& seasoning = ingredients["seasoning"].GetArray()[0].GetObject();
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^

Я предполагаю, что вы намеревались иметь массив объектов, а не массив с одним объектом.

Это:

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

, а не это:

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

Вы должны манипулировать этим соответствующим образом в коде также.

0 голосов
/ 13 февраля 2020

Если вам нужно проверить только, заканчивается ли строка известным значением, это довольно просто сделать, сравнив ее без библиотек подстановочных знаков:

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;
        }
    }
}

Если вам нужно сопоставить более сложные шаблоны, тогда вы можно использовать std :: regex

...