Take care of default values for validation
validation may depend on default values in case of "if, ..." statements. Therefore, validation operates on a copy and adds default values. In alternative, it serves a validate_and_fill which avoids a copy.
This commit is contained in:
parent
6709194813
commit
0dca07bdf8
@ -13,7 +13,6 @@ add_library(nlohmann_json_schema_validator
|
|||||||
src/json-schema-draft7.json.cpp
|
src/json-schema-draft7.json.cpp
|
||||||
src/json-uri.cpp
|
src/json-uri.cpp
|
||||||
src/json-validator.cpp
|
src/json-validator.cpp
|
||||||
src/json-patch.cpp
|
|
||||||
src/string-format-check.cpp)
|
src/string-format-check.cpp)
|
||||||
|
|
||||||
target_include_directories(nlohmann_json_schema_validator
|
target_include_directories(nlohmann_json_schema_validator
|
||||||
|
|||||||
@ -1,78 +0,0 @@
|
|||||||
#include "json-patch.hpp"
|
|
||||||
|
|
||||||
namespace nlohmann
|
|
||||||
{
|
|
||||||
|
|
||||||
json_patch::json_patch()
|
|
||||||
: j_{R"([])"_json} {}
|
|
||||||
|
|
||||||
json_patch::json_patch(json &&patch)
|
|
||||||
: j_{std::move(patch)}
|
|
||||||
{
|
|
||||||
validateJsonPatch(j_);
|
|
||||||
}
|
|
||||||
|
|
||||||
json_patch::json_patch(const json &patch)
|
|
||||||
: j_{std::move(patch)}
|
|
||||||
{
|
|
||||||
validateJsonPatch(j_);
|
|
||||||
}
|
|
||||||
|
|
||||||
json_patch &json_patch::add(std::string path, json value)
|
|
||||||
{
|
|
||||||
j_.push_back(json{{"op", "add"}, {"path", std::move(path)}, {"value", std::move(value)}});
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
json_patch &json_patch::replace(std::string path, json value)
|
|
||||||
{
|
|
||||||
j_.push_back(json{{"op", "replace"}, {"path", std::move(path)}, {"value", std::move(value)}});
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
json_patch &json_patch::remove(std::string path)
|
|
||||||
{
|
|
||||||
j_.push_back(json{{"op", "remove"}, {"path", std::move(path)}});
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void json_patch::validateJsonPatch(json const &patch)
|
|
||||||
{
|
|
||||||
if (!patch.is_array()) {
|
|
||||||
throw JsonPatchFormatException{"Json is not an array"};
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto const &op : patch) {
|
|
||||||
if (!op.is_object()) {
|
|
||||||
throw JsonPatchFormatException{"Each json patch entry needs to be an op object"};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!op.contains("op")) {
|
|
||||||
throw JsonPatchFormatException{"Each json patch entry needs op element"};
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto opType = op["op"].get<std::string>();
|
|
||||||
if ((opType != "add") && (opType != "remove") && (opType != "replace")) {
|
|
||||||
throw JsonPatchFormatException{std::string{"Operation "} + opType + std::string{"is invalid"}};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!op.contains("path")) {
|
|
||||||
throw JsonPatchFormatException{"Each json patch entry needs path element"};
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// try parse to path
|
|
||||||
[[maybe_unused]] const auto p = json::json_pointer{op["path"].get<std::string>()};
|
|
||||||
} catch (json::exception &e) {
|
|
||||||
throw JsonPatchFormatException{e.what()};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opType != "remove") {
|
|
||||||
if (!op.contains("value")) {
|
|
||||||
throw JsonPatchFormatException{"Remove and replace needs value element"};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace nlohmann
|
|
||||||
@ -1,38 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace nlohmann
|
|
||||||
{
|
|
||||||
class JsonPatchFormatException : public std::exception
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit JsonPatchFormatException(std::string msg)
|
|
||||||
: ex_{std::move(msg)} {}
|
|
||||||
|
|
||||||
inline const char *what() const noexcept override final { return ex_.c_str(); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string ex_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class json_patch
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
json_patch();
|
|
||||||
json_patch(json &&patch);
|
|
||||||
json_patch(const json &patch);
|
|
||||||
|
|
||||||
json_patch &add(std::string path, json value);
|
|
||||||
json_patch &replace(std::string path, json value);
|
|
||||||
json_patch &remove(std::string path);
|
|
||||||
|
|
||||||
operator json() const { return j_; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
json j_;
|
|
||||||
|
|
||||||
static void validateJsonPatch(json const &patch);
|
|
||||||
};
|
|
||||||
} // namespace nlohmann
|
|
||||||
@ -8,14 +8,12 @@
|
|||||||
*/
|
*/
|
||||||
#include <nlohmann/json-schema.hpp>
|
#include <nlohmann/json-schema.hpp>
|
||||||
|
|
||||||
#include "json-patch.hpp"
|
#include <iostream>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
using nlohmann::json;
|
using nlohmann::json;
|
||||||
using nlohmann::json_patch;
|
|
||||||
using nlohmann::json_uri;
|
using nlohmann::json_uri;
|
||||||
using nlohmann::json_schema::root_schema;
|
using nlohmann::json_schema::root_schema;
|
||||||
using namespace nlohmann::json_schema;
|
using namespace nlohmann::json_schema;
|
||||||
@ -46,7 +44,7 @@ public:
|
|||||||
schema(root_schema *root)
|
schema(root_schema *root)
|
||||||
: root_(root) {}
|
: root_(root) {}
|
||||||
|
|
||||||
virtual void validate(const json::json_pointer &ptr, const json &instance, json_patch &patch, error_handler &e) const = 0;
|
virtual void validate(const json::json_pointer &ptr, json &instance, error_handler &e) const = 0;
|
||||||
|
|
||||||
virtual const json &defaultValue(const json::json_pointer &, const json &, error_handler &) const
|
virtual const json &defaultValue(const json::json_pointer &, const json &, error_handler &) const
|
||||||
{
|
{
|
||||||
@ -64,10 +62,10 @@ class schema_ref : public schema
|
|||||||
const std::string id_;
|
const std::string id_;
|
||||||
std::shared_ptr<schema> target_;
|
std::shared_ptr<schema> target_;
|
||||||
|
|
||||||
void validate(const json::json_pointer &ptr, const json &instance, json_patch &patch, error_handler &e) const final
|
void validate(const json::json_pointer &ptr, json &instance, error_handler &e) const final
|
||||||
{
|
{
|
||||||
if (target_)
|
if (target_)
|
||||||
target_->validate(ptr, instance, patch, e);
|
target_->validate(ptr, instance, e);
|
||||||
else
|
else
|
||||||
e.error(ptr, instance, "unresolved schema-reference " + id_);
|
e.error(ptr, instance, "unresolved schema-reference " + id_);
|
||||||
}
|
}
|
||||||
@ -230,10 +228,10 @@ public:
|
|||||||
} while (1);
|
} while (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void validate(const json::json_pointer &ptr, const json &instance, json_patch &patch, error_handler &e) const final
|
void validate(const json::json_pointer &ptr, json &instance, error_handler &e) const final
|
||||||
{
|
{
|
||||||
if (root_)
|
if (root_)
|
||||||
root_->validate(ptr, instance, patch, e);
|
root_->validate(ptr, instance, e);
|
||||||
else
|
else
|
||||||
e.error(ptr, "", "no root schema has yet been set for validating an instance");
|
e.error(ptr, "", "no root schema has yet been set for validating an instance");
|
||||||
}
|
}
|
||||||
@ -280,10 +278,10 @@ class logical_not : public schema
|
|||||||
{
|
{
|
||||||
std::shared_ptr<schema> subschema_;
|
std::shared_ptr<schema> subschema_;
|
||||||
|
|
||||||
void validate(const json::json_pointer &ptr, const json &instance, json_patch &patch, error_handler &e) const final
|
void validate(const json::json_pointer &ptr, json &instance, error_handler &e) const final
|
||||||
{
|
{
|
||||||
first_error_handler esub;
|
first_error_handler esub;
|
||||||
subschema_->validate(ptr, instance, patch, esub);
|
subschema_->validate(ptr, instance, esub);
|
||||||
|
|
||||||
if (!esub)
|
if (!esub)
|
||||||
e.error(ptr, instance, "the subschema has succeeded, but it is required to not validate");
|
e.error(ptr, instance, "the subschema has succeeded, but it is required to not validate");
|
||||||
@ -315,13 +313,13 @@ class logical_combination : public schema
|
|||||||
{
|
{
|
||||||
std::vector<std::shared_ptr<schema>> subschemata_;
|
std::vector<std::shared_ptr<schema>> subschemata_;
|
||||||
|
|
||||||
void validate(const json::json_pointer &ptr, const json &instance, json_patch &patch, error_handler &e) const final
|
void validate(const json::json_pointer &ptr, json &instance, error_handler &e) const final
|
||||||
{
|
{
|
||||||
size_t count = 0;
|
size_t count = 0;
|
||||||
|
|
||||||
for (auto &s : subschemata_) {
|
for (auto &s : subschemata_) {
|
||||||
first_error_handler esub;
|
first_error_handler esub;
|
||||||
s->validate(ptr, instance, patch, esub);
|
s->validate(ptr, instance, esub);
|
||||||
if (!esub)
|
if (!esub)
|
||||||
count++;
|
count++;
|
||||||
|
|
||||||
@ -403,13 +401,13 @@ class type_schema : public schema
|
|||||||
return defaultValue_;
|
return defaultValue_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void validate(const json::json_pointer &ptr, const json &instance, json_patch &patch, error_handler &e) const override final
|
void validate(const json::json_pointer &ptr, json &instance, error_handler &e) const override final
|
||||||
{
|
{
|
||||||
// depending on the type of instance run the type specific validator - if present
|
// depending on the type of instance run the type specific validator - if present
|
||||||
auto type = type_[(uint8_t) instance.type()];
|
auto type = type_[(uint8_t) instance.type()];
|
||||||
|
|
||||||
if (type)
|
if (type)
|
||||||
type->validate(ptr, instance, patch, e);
|
type->validate(ptr, instance, e);
|
||||||
else
|
else
|
||||||
e.error(ptr, instance, "unexpected instance type");
|
e.error(ptr, instance, "unexpected instance type");
|
||||||
|
|
||||||
@ -430,18 +428,18 @@ class type_schema : public schema
|
|||||||
e.error(ptr, instance, "instance not const");
|
e.error(ptr, instance, "instance not const");
|
||||||
|
|
||||||
for (auto l : logic_)
|
for (auto l : logic_)
|
||||||
l->validate(ptr, instance, patch, e);
|
l->validate(ptr, instance, e);
|
||||||
|
|
||||||
if (if_) {
|
if (if_) {
|
||||||
first_error_handler err;
|
first_error_handler err;
|
||||||
|
|
||||||
if_->validate(ptr, instance, patch, err);
|
if_->validate(ptr, instance, err);
|
||||||
if (!err) {
|
if (!err) {
|
||||||
if (then_)
|
if (then_)
|
||||||
then_->validate(ptr, instance, patch, e);
|
then_->validate(ptr, instance, e);
|
||||||
} else {
|
} else {
|
||||||
if (else_)
|
if (else_)
|
||||||
else_->validate(ptr, instance, patch, e);
|
else_->validate(ptr, instance, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -590,7 +588,7 @@ class string : public schema
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
void validate(const json::json_pointer &ptr, const json &instance, json_patch &, error_handler &e) const override
|
void validate(const json::json_pointer &ptr, json &instance, error_handler &e) const override
|
||||||
{
|
{
|
||||||
if (minLength_.first) {
|
if (minLength_.first) {
|
||||||
if (utf8_length(instance) < minLength_.second) {
|
if (utf8_length(instance) < minLength_.second) {
|
||||||
@ -680,7 +678,7 @@ class numeric : public schema
|
|||||||
return std::fabs(res) > std::fabs(eps);
|
return std::fabs(res) > std::fabs(eps);
|
||||||
}
|
}
|
||||||
|
|
||||||
void validate(const json::json_pointer &ptr, const json &instance, json_patch &, error_handler &e) const override
|
void validate(const json::json_pointer &ptr, json &instance, error_handler &e) const override
|
||||||
{
|
{
|
||||||
T value = instance; // conversion of json to value_type
|
T value = instance; // conversion of json to value_type
|
||||||
|
|
||||||
@ -739,7 +737,7 @@ public:
|
|||||||
|
|
||||||
class null : public schema
|
class null : public schema
|
||||||
{
|
{
|
||||||
void validate(const json::json_pointer &ptr, const json &instance, json_patch &, error_handler &e) const override
|
void validate(const json::json_pointer &ptr, json &instance, error_handler &e) const override
|
||||||
{
|
{
|
||||||
if (!instance.is_null())
|
if (!instance.is_null())
|
||||||
e.error(ptr, instance, "expected to be null");
|
e.error(ptr, instance, "expected to be null");
|
||||||
@ -752,7 +750,7 @@ public:
|
|||||||
|
|
||||||
class boolean_type : public schema
|
class boolean_type : public schema
|
||||||
{
|
{
|
||||||
void validate(const json::json_pointer &, const json &, json_patch &, error_handler &) const override {}
|
void validate(const json::json_pointer &, json &, error_handler &) const override {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
boolean_type(json &, root_schema *root)
|
boolean_type(json &, root_schema *root)
|
||||||
@ -762,7 +760,7 @@ public:
|
|||||||
class boolean : public schema
|
class boolean : public schema
|
||||||
{
|
{
|
||||||
bool true_;
|
bool true_;
|
||||||
void validate(const json::json_pointer &ptr, const json &instance, json_patch &, error_handler &e) const override
|
void validate(const json::json_pointer &ptr, json &instance, error_handler &e) const override
|
||||||
{
|
{
|
||||||
if (!true_) { // false schema
|
if (!true_) { // false schema
|
||||||
// empty array
|
// empty array
|
||||||
@ -786,7 +784,7 @@ class required : public schema
|
|||||||
{
|
{
|
||||||
const std::vector<std::string> required_;
|
const std::vector<std::string> required_;
|
||||||
|
|
||||||
void validate(const json::json_pointer &ptr, const json &instance, json_patch &, error_handler &e) const override final
|
void validate(const json::json_pointer &ptr, json &instance, error_handler &e) const override final
|
||||||
{
|
{
|
||||||
for (auto &r : required_)
|
for (auto &r : required_)
|
||||||
if (instance.find(r) == instance.end())
|
if (instance.find(r) == instance.end())
|
||||||
@ -814,7 +812,7 @@ class object : public schema
|
|||||||
|
|
||||||
std::shared_ptr<schema> propertyNames_;
|
std::shared_ptr<schema> propertyNames_;
|
||||||
|
|
||||||
void validate(const json::json_pointer &ptr, const json &instance, json_patch &patch, error_handler &e) const override
|
void validate(const json::json_pointer &ptr, json &instance, error_handler &e) const override
|
||||||
{
|
{
|
||||||
if (maxProperties_.first && instance.size() > maxProperties_.second)
|
if (maxProperties_.first && instance.size() > maxProperties_.second)
|
||||||
e.error(ptr, instance, "too many properties");
|
e.error(ptr, instance, "too many properties");
|
||||||
@ -828,15 +826,17 @@ class object : public schema
|
|||||||
|
|
||||||
// for each property in instance
|
// for each property in instance
|
||||||
for (auto &p : instance.items()) {
|
for (auto &p : instance.items()) {
|
||||||
if (propertyNames_)
|
if (propertyNames_) {
|
||||||
propertyNames_->validate(ptr, p.key(), patch, e);
|
json v = p.key();
|
||||||
|
propertyNames_->validate(ptr, v, e);
|
||||||
|
}
|
||||||
|
|
||||||
bool a_prop_or_pattern_matched = false;
|
bool a_prop_or_pattern_matched = false;
|
||||||
auto schema_p = properties_.find(p.key());
|
auto schema_p = properties_.find(p.key());
|
||||||
// check if it is in "properties"
|
// check if it is in "properties"
|
||||||
if (schema_p != properties_.end()) {
|
if (schema_p != properties_.end()) {
|
||||||
a_prop_or_pattern_matched = true;
|
a_prop_or_pattern_matched = true;
|
||||||
schema_p->second->validate(ptr / p.key(), p.value(), patch, e);
|
schema_p->second->validate(ptr / p.key(), p.value(), e);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef NO_STD_REGEX
|
#ifndef NO_STD_REGEX
|
||||||
@ -844,14 +844,14 @@ class object : public schema
|
|||||||
for (auto &schema_pp : patternProperties_)
|
for (auto &schema_pp : patternProperties_)
|
||||||
if (REGEX_NAMESPACE::regex_search(p.key(), schema_pp.first)) {
|
if (REGEX_NAMESPACE::regex_search(p.key(), schema_pp.first)) {
|
||||||
a_prop_or_pattern_matched = true;
|
a_prop_or_pattern_matched = true;
|
||||||
schema_pp.second->validate(ptr / p.key(), p.value(), patch, e);
|
schema_pp.second->validate(ptr / p.key(), p.value(), e);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// check additionalProperties as a last resort
|
// check additionalProperties as a last resort
|
||||||
if (!a_prop_or_pattern_matched && additionalProperties_) {
|
if (!a_prop_or_pattern_matched && additionalProperties_) {
|
||||||
first_error_handler additional_prop_err;
|
first_error_handler additional_prop_err;
|
||||||
additionalProperties_->validate(ptr / p.key(), p.value(), patch, additional_prop_err);
|
additionalProperties_->validate(ptr / p.key(), p.value(), additional_prop_err);
|
||||||
if (additional_prop_err)
|
if (additional_prop_err)
|
||||||
e.error(ptr, instance, "validation failed for additional property '" + p.key() + "': " + additional_prop_err.message_);
|
e.error(ptr, instance, "validation failed for additional property '" + p.key() + "': " + additional_prop_err.message_);
|
||||||
}
|
}
|
||||||
@ -863,7 +863,7 @@ class object : public schema
|
|||||||
if (instance.end() == finding) { // if the prop is not in the instance
|
if (instance.end() == finding) { // if the prop is not in the instance
|
||||||
const auto &defaultValue = prop.second->defaultValue(ptr, instance, e);
|
const auto &defaultValue = prop.second->defaultValue(ptr, instance, e);
|
||||||
if (!defaultValue.empty()) { // if default value is available
|
if (!defaultValue.empty()) { // if default value is available
|
||||||
patch.add((ptr / prop.first), defaultValue);
|
instance[prop.first] = defaultValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -871,7 +871,7 @@ class object : public schema
|
|||||||
for (auto &dep : dependencies_) {
|
for (auto &dep : dependencies_) {
|
||||||
auto prop = instance.find(dep.first);
|
auto prop = instance.find(dep.first);
|
||||||
if (prop != instance.end()) // if dependency-property is present in instance
|
if (prop != instance.end()) // if dependency-property is present in instance
|
||||||
dep.second->validate(ptr / dep.first, instance, patch, e); // validate
|
dep.second->validate(ptr / dep.first, instance, e); // validate
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -966,7 +966,7 @@ class array : public schema
|
|||||||
|
|
||||||
std::shared_ptr<schema> contains_;
|
std::shared_ptr<schema> contains_;
|
||||||
|
|
||||||
void validate(const json::json_pointer &ptr, const json &instance, json_patch &patch, error_handler &e) const override
|
void validate(const json::json_pointer &ptr, json &instance, error_handler &e) const override
|
||||||
{
|
{
|
||||||
if (maxItems_.first && instance.size() > maxItems_.second)
|
if (maxItems_.first && instance.size() > maxItems_.second)
|
||||||
e.error(ptr, instance, "array has too many items");
|
e.error(ptr, instance, "array has too many items");
|
||||||
@ -976,7 +976,7 @@ class array : public schema
|
|||||||
|
|
||||||
if (uniqueItems_) {
|
if (uniqueItems_) {
|
||||||
for (auto it = instance.cbegin(); it != instance.cend(); ++it) {
|
for (auto it = instance.cbegin(); it != instance.cend(); ++it) {
|
||||||
auto v = std::find(it + 1, instance.end(), *it);
|
auto v = std::find(it + 1, instance.cend(), *it);
|
||||||
if (v != instance.end())
|
if (v != instance.end())
|
||||||
e.error(ptr, instance, "items have to be unique for this array");
|
e.error(ptr, instance, "items have to be unique for this array");
|
||||||
}
|
}
|
||||||
@ -985,7 +985,7 @@ class array : public schema
|
|||||||
size_t index = 0;
|
size_t index = 0;
|
||||||
if (items_schema_)
|
if (items_schema_)
|
||||||
for (auto &i : instance) {
|
for (auto &i : instance) {
|
||||||
items_schema_->validate(ptr / index, i, patch, e);
|
items_schema_->validate(ptr / index, i, e);
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -1002,7 +1002,7 @@ class array : public schema
|
|||||||
if (!item_validator)
|
if (!item_validator)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
item_validator->validate(ptr / index, i, patch, e);
|
item_validator->validate(ptr / index, i, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1010,7 +1010,7 @@ class array : public schema
|
|||||||
bool contained = false;
|
bool contained = false;
|
||||||
for (auto &item : instance) {
|
for (auto &item : instance) {
|
||||||
first_error_handler local_e;
|
first_error_handler local_e;
|
||||||
contains_->validate(ptr, item, patch, local_e);
|
contains_->validate(ptr, item, local_e);
|
||||||
if (!local_e) {
|
if (!local_e) {
|
||||||
contained = true;
|
contained = true;
|
||||||
break;
|
break;
|
||||||
@ -1227,9 +1227,21 @@ json json_validator::validate(const json &instance) const
|
|||||||
json json_validator::validate(const json &instance, error_handler &err) const
|
json json_validator::validate(const json &instance, error_handler &err) const
|
||||||
{
|
{
|
||||||
json::json_pointer ptr;
|
json::json_pointer ptr;
|
||||||
json_patch patch{};
|
json cpy = instance;
|
||||||
root_->validate(ptr, instance, patch, err);
|
root_->validate(ptr, cpy, err);
|
||||||
return patch;
|
return json::diff(instance, cpy);
|
||||||
|
}
|
||||||
|
|
||||||
|
void json_validator::validate_and_fill(json &instance) const
|
||||||
|
{
|
||||||
|
throwing_error_handler err;
|
||||||
|
validate_and_fill(instance, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
void json_validator::validate_and_fill(json &instance, error_handler &err) const
|
||||||
|
{
|
||||||
|
json::json_pointer ptr;
|
||||||
|
root_->validate(ptr, instance, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace json_schema
|
} // namespace json_schema
|
||||||
|
|||||||
@ -190,6 +190,12 @@ public:
|
|||||||
|
|
||||||
// validate a json-document based on the root-schema with a custom error-handler
|
// validate a json-document based on the root-schema with a custom error-handler
|
||||||
json validate(const json &, error_handler &) const;
|
json validate(const json &, error_handler &) const;
|
||||||
|
|
||||||
|
// validate a json-document based on the root-schema. It fills the document with default values where specified in the schema.
|
||||||
|
void validate_and_fill(json &) const;
|
||||||
|
|
||||||
|
// validate a json-document based on the root-schema with a custom error-handler. It fills the document with default values where specified in the schema.
|
||||||
|
void validate_and_fill(json &, error_handler &) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace json_schema
|
} // namespace json_schema
|
||||||
|
|||||||
@ -37,7 +37,7 @@ static const json person_schema = R"(
|
|||||||
"type": "object"
|
"type": "object"
|
||||||
})"_json;
|
})"_json;
|
||||||
|
|
||||||
int main(void)
|
int immutable_validation()
|
||||||
{
|
{
|
||||||
json_validator validator{};
|
json_validator validator{};
|
||||||
|
|
||||||
@ -95,6 +95,43 @@ int main(void)
|
|||||||
std::cerr << "Patch with defaults contains wrong value" << std::endl;
|
std::cerr << "Patch with defaults contains wrong value" << std::endl;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int validation_and_fill()
|
||||||
|
{
|
||||||
|
json_validator validator{};
|
||||||
|
|
||||||
|
// add address which is optional that should generate a diff containing a default street
|
||||||
|
json person_missing_address = R"({
|
||||||
|
"name": "Knut",
|
||||||
|
"age": 12,
|
||||||
|
"address": {}
|
||||||
|
})"_json;
|
||||||
|
|
||||||
|
validator.set_root_schema(person_schema);
|
||||||
|
|
||||||
|
validator.validate_and_fill(person_missing_address);
|
||||||
|
|
||||||
|
if (!person_missing_address.contains("/address/street"_json_pointer)) {
|
||||||
|
std::cerr << "Validated document should contain default value" << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (person_missing_address["/address/street"_json_pointer].get<std::string>() != "Abbey Road") {
|
||||||
|
std::cerr << "Validated document with defaults contains wrong value" << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
ret += immutable_validation();
|
||||||
|
ret += validation_and_fill();
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user