Как проанализировать действительный файл JSON, который имеет недопустимое поле внутри? - PullRequest
2 голосов
/ 07 апреля 2020

Я знаю, что это может показаться странным вопросом, но вход моего алгоритма представляет собой поток JSON строк, составленных из синтаксически правильных блоков JSON, по крайней мере для всех блоков, кроме этого. Блок в потоке имеет такую ​​структуру:

{
  "comment",
  {
    "author":"X",
    "body":"Hello world",
    "json_metadata":"{\"tags\":[\"hello, world\"],\"community\":\"programming\",\"app\":\"application_for_publish\"}",
    "parent_author":"waggy6",
    "parent_permlink":"programming_in_c",
    "permlink":"re-author-programming_in_c-20180916t035418244z",
    "title":"some_title"
  }
}

Итак, все работает нормально, вплоть до прибытия в этот блок, что я не знаю, как анализировать. Поле, которое доставляет мне неприятности, это "json_metadata" one:

{
  "comment", 
  {
    "author": "Y",
    "body": "Hello another world!",
    "json_metadata": "\"{\\\"tags\\\":[\\\"hello\\\",\\\"world\\\"],\\\"app\\\":\\\"application_for_publish_content\\\",\\\"format\\\":\\\"markdown+html\\\",\\\"pollid\\\":\\\"p_id\\\",\\\"image\\\":[\\\"https://un.useful.url/path/image.png\\\"]}\"",
    "parent_author": "",
    "parent_permlink": "helloworld",
    "permlink": "hello_world_programming_in_c-2017319t94958596z",
    "title": "Hello World in C!"
  }
}

Как будто это поле было проанализировано дважды, когда были получены данные. Я использую rapidjson в качестве инструмента синтаксического анализа, в C ++. Часть кода, связанная с этой проблемой, выглядит следующим образом:

static std::string parseNode(const Value &node){
   string toret = "";
   if (node.IsBool())          toret = toret + to_string(node.GetBool());
   else if (node.IsInt())      toret = toret + to_string(node.GetInt());
   else if (node.IsUint())     toret = toret + to_string(node.GetUint());
   else if (node.IsInt64())    toret = toret + to_string(node.GetInt64());
   else if (node.IsUint64())   toret = toret + to_string(node.GetUint64());
   else if (node.IsDouble())   toret = toret + to_string(node.GetDouble());
   else if (node.IsString())   toret = toret + node.GetString();
   else if (node.IsArray())    toret = toret + parseArray(node); // parse the given array
   else if (node.IsObject())   toret = toret + parseObject(node); // parse the given object
   return toret;
}

...

std::string search_member(Value& js, std::string member){
   Value::ConstMemberIterator itr = js.FindMember(member.c_str());
   std::string els = "";
   if(itr != js.MemberEnd())
      els = parseNode(itr->value) + " ";
   return els;
}

...

// op_struct type is Value*; it is the Value* that refers to all the fields of the block
std::string json_m = (*op_struct)["json_metadata"];
std::string elements = "";
if((json_m.compare("") != 0) && (json_m.compare("{}") != 0) && (json_m.compare("\"\"") != 0)){
   Document js;
   js.Parse<0>(json_m.c_str());
   elements = elements + search_member(js, "community") + search_member(js, "tags") + search_member(js, "app");
}
Comment * comment = new Comment(title + " " + body + " " + elements, auth);

...

Проблема возникает в строке js.FindMember(member.c_str());, в функции search_member(), поскольку js.Parse<0>(json_m.c_str()); распознает, что вход является допустимым JSON, и действительно это действительно, это относится к:

"\"{\\\"tags\\\":[\\\"hello\\\",\\\"world\\\"],\\\"app\\\":\\\"application_for_publish_content\\\",\\\"format\\\":\\\"markdown+html\\\",\\\"pollid\\\":\\\"p_id\\\",\\\"image\\\":[\\\"https://un.useful.url/path/image.png\\\"]}\""

Но тогда результатом этого вычисления является строка:

"{\"tags\":[\"hello\",\"world\"],\"app\":\"application_for_publish_content\",\"format\":\"markdown+html\",\"pollid\":\"p_id\",\"image\"

И по этой причине функция FindMember() не может найти ни одного поля tags, community или app, поскольку оно распознается как строка.

Мой вопрос является: есть ли способ (отличается, просто пропустив этот блок), с помощью которого я могу распознать такие особые случаи?

...