如何验证 RapidJSON 文档的子集?
How can I validate a subset of a RapidJSON document?
我正在使用 RapidJSON 来解析(大致)符合 JSON-RPC 的消息。下面是这样一条消息的示例:
{
"method": "increment",
"params": [ { "count": 42 } ]
}
params
的内容取决于 method
的值,所以...我需要针对 method
的每个可能值针对不同的模式进行验证。作为朝着这个目标迈出的一步,我创建了一个模式文档映射,以 method
名称作为键:
std::unordered_map<std::string, rapidjson::SchemaDocument> schemas;
我的意图是做这样的事情(在将收到的 JSON 解析为 RapidJSON 文档后,doc
):
if (schemas.find(doc["method"]) != schemas.end()) {
validate(doc, schemas[doc]);
}
我的问题是:我知道如何验证 rapidjson::Document
,但不知道 GenericValue
实例(据我所知,doc["method"]
returns)。
如何验证 RapidJSON 文档的片段或 'sub-document'?
UPDATE/EXPLANATION:感谢@wsxedcrfv 的回答,我现在意识到我说“我知道如何验证 rapidjson::Document
的说法并不完全准确。我知道 一种 验证 rapidjson::Document
的方法。但显然有不止一种方法可以做到这一点。为了后代解决这个问题,这里是 validate()
我原来的问题中缺少的功能:
bool validate(
rj::SchemaDocument const& schema,
rj::Document *doc,
std::string const& jsonMsg
)
{
bool valid = false;
rj::StringStream ss(jsonMsg.c_str());
rj::SchemaValidatingReader<
rj::kParseDefaultFlags,
rj::StringStream,
rj::UTF8<>
> reader(ss, schema);
doc->Populate(reader);
if (!reader.GetParseResult()) {
if (!reader.IsValid()) {
rj::StringBuffer sb;
reader.GetInvalidSchemaPointer().StringifyUriFragment(sb);
printf("Message does not conform to schema!\n");
printf("--------------------------------------------------------------------\n");
printf("Invalid schema: %s\n", sb.GetString());
printf("Invalid keyword: %s\n", reader.GetInvalidSchemaKeyword());
sb.Clear();
reader.GetInvalidDocumentPointer().StringifyUriFragment(sb);
printf("Invalid document: %s\n", sb.GetString());
printf("--------------------------------------------------------------------\n");
}
else {
printf("Message JSON is not well-formed!\n");
}
}
else {
valid = true;
}
return valid;
}
正如@wsxedcrfv 指出的那样,另一种选择是创建一个 SchemaValidator
实例并将其传递给(子)文档的 Accept()
方法:
#include "rapidjson/document.h"
#include <rapidjson/schema.h>
#include <iostream>
namespace rj = rapidjson;
namespace
{
std::string testMsg = R"msg({ "root": { "method": "control", "params": [ { "icc_delta_vol": 5 } ] } })msg";
std::string msgSchema = R"schema(
{
"type": "object",
"properties": {
"method": { "$ref": "#/definitions/method" },
"params": { "$ref": "#/definitions/paramsList" }
},
"required": [ "method", "params" ],
"additionalProperties": false,
"definitions": {
// Omitted in the interest of brevity
...
}
})schema";
} // End anonymous namespace
int main()
{
rj::Document schemaDoc;
if (schemaDoc.Parse(::msgSchema.c_str()).HasParseError()) {
std::cout << "Schema contains invalid JSON, aborting...\n";
exit(EXIT_FAILURE);
}
rj::SchemaDocument schema(schemaDoc);
rj::SchemaValidator validator(schema);
rj::Document doc;
doc.Parse(::testMsg.c_str());
std::cout << "doc.Accept(validator) = " << doc["root"].Accept(validator) << '\n';
return 0;
现在我知道了这种替代方法,我可以轻松地使用它来对 sub-documents/fragments...
进行特定于上下文的验证
我想这个答案对你来说有点晚了,但这对我有用:
char json[] = "{ \"a\" : 1, \"b\" : 1.2 } ";
rapidjson::Document d;
std::cout << "parse json error? " << d.Parse(json).HasParseError() << "\n";
char schema[] = "{ \"type\" : \"integer\" } ";
rapidjson::Document sd;
std::cout << "parse schema error? " << sd.Parse(schema).HasParseError() << "\n";
rapidjson::SchemaDocument s{sd}; //sd may now be deleted
rapidjson::SchemaValidator vali{s};
std::cout << "json " << d.Accept(vali) << "\n"; // 0
vali.Reset();
std::cout << "a " << d.GetObject()["a"].Accept(vali) << "\n"; // 1
vali.Reset();
std::cout << "b " << d.GetObject()["b"].Accept(vali) << "\n"; // 0
我不知道您使用的是哪个 validate
函数,但是 Document
是 GenericValue
而 GenericValue
提供 Accept
。
我正在使用 RapidJSON 来解析(大致)符合 JSON-RPC 的消息。下面是这样一条消息的示例:
{
"method": "increment",
"params": [ { "count": 42 } ]
}
params
的内容取决于 method
的值,所以...我需要针对 method
的每个可能值针对不同的模式进行验证。作为朝着这个目标迈出的一步,我创建了一个模式文档映射,以 method
名称作为键:
std::unordered_map<std::string, rapidjson::SchemaDocument> schemas;
我的意图是做这样的事情(在将收到的 JSON 解析为 RapidJSON 文档后,doc
):
if (schemas.find(doc["method"]) != schemas.end()) {
validate(doc, schemas[doc]);
}
我的问题是:我知道如何验证 rapidjson::Document
,但不知道 GenericValue
实例(据我所知,doc["method"]
returns)。
如何验证 RapidJSON 文档的片段或 'sub-document'?
UPDATE/EXPLANATION:感谢@wsxedcrfv 的回答,我现在意识到我说“我知道如何验证 rapidjson::Document
的说法并不完全准确。我知道 一种 验证 rapidjson::Document
的方法。但显然有不止一种方法可以做到这一点。为了后代解决这个问题,这里是 validate()
我原来的问题中缺少的功能:
bool validate(
rj::SchemaDocument const& schema,
rj::Document *doc,
std::string const& jsonMsg
)
{
bool valid = false;
rj::StringStream ss(jsonMsg.c_str());
rj::SchemaValidatingReader<
rj::kParseDefaultFlags,
rj::StringStream,
rj::UTF8<>
> reader(ss, schema);
doc->Populate(reader);
if (!reader.GetParseResult()) {
if (!reader.IsValid()) {
rj::StringBuffer sb;
reader.GetInvalidSchemaPointer().StringifyUriFragment(sb);
printf("Message does not conform to schema!\n");
printf("--------------------------------------------------------------------\n");
printf("Invalid schema: %s\n", sb.GetString());
printf("Invalid keyword: %s\n", reader.GetInvalidSchemaKeyword());
sb.Clear();
reader.GetInvalidDocumentPointer().StringifyUriFragment(sb);
printf("Invalid document: %s\n", sb.GetString());
printf("--------------------------------------------------------------------\n");
}
else {
printf("Message JSON is not well-formed!\n");
}
}
else {
valid = true;
}
return valid;
}
正如@wsxedcrfv 指出的那样,另一种选择是创建一个 SchemaValidator
实例并将其传递给(子)文档的 Accept()
方法:
#include "rapidjson/document.h"
#include <rapidjson/schema.h>
#include <iostream>
namespace rj = rapidjson;
namespace
{
std::string testMsg = R"msg({ "root": { "method": "control", "params": [ { "icc_delta_vol": 5 } ] } })msg";
std::string msgSchema = R"schema(
{
"type": "object",
"properties": {
"method": { "$ref": "#/definitions/method" },
"params": { "$ref": "#/definitions/paramsList" }
},
"required": [ "method", "params" ],
"additionalProperties": false,
"definitions": {
// Omitted in the interest of brevity
...
}
})schema";
} // End anonymous namespace
int main()
{
rj::Document schemaDoc;
if (schemaDoc.Parse(::msgSchema.c_str()).HasParseError()) {
std::cout << "Schema contains invalid JSON, aborting...\n";
exit(EXIT_FAILURE);
}
rj::SchemaDocument schema(schemaDoc);
rj::SchemaValidator validator(schema);
rj::Document doc;
doc.Parse(::testMsg.c_str());
std::cout << "doc.Accept(validator) = " << doc["root"].Accept(validator) << '\n';
return 0;
现在我知道了这种替代方法,我可以轻松地使用它来对 sub-documents/fragments...
进行特定于上下文的验证我想这个答案对你来说有点晚了,但这对我有用:
char json[] = "{ \"a\" : 1, \"b\" : 1.2 } ";
rapidjson::Document d;
std::cout << "parse json error? " << d.Parse(json).HasParseError() << "\n";
char schema[] = "{ \"type\" : \"integer\" } ";
rapidjson::Document sd;
std::cout << "parse schema error? " << sd.Parse(schema).HasParseError() << "\n";
rapidjson::SchemaDocument s{sd}; //sd may now be deleted
rapidjson::SchemaValidator vali{s};
std::cout << "json " << d.Accept(vali) << "\n"; // 0
vali.Reset();
std::cout << "a " << d.GetObject()["a"].Accept(vali) << "\n"; // 1
vali.Reset();
std::cout << "b " << d.GetObject()["b"].Accept(vali) << "\n"; // 0
我不知道您使用的是哪个 validate
函数,但是 Document
是 GenericValue
而 GenericValue
提供 Accept
。