2013-10-29 21:51:11 +01:00
|
|
|
/**
|
|
|
|
* @file
|
|
|
|
*
|
|
|
|
* @brief Demonstrates validation against a manually constructed schema.
|
|
|
|
*
|
|
|
|
* This example demonstrates the construction and composition of a Schema object
|
|
|
|
* using manually created Constraint objects. The following Constraint classes
|
|
|
|
* are used:
|
|
|
|
* - EnumConstraint
|
|
|
|
* - MaxLengthConstraint
|
|
|
|
* - MinimumConstraint
|
|
|
|
* - MinLengthConstraint
|
|
|
|
* - PropertiesConstraint
|
|
|
|
* - RequiredConstraint
|
|
|
|
* - TypeConstraint
|
2014-02-28 23:03:39 +01:00
|
|
|
*
|
2013-10-29 21:51:11 +01:00
|
|
|
* The MinimumConstraint class provides support for the exclusiveMinimum and
|
|
|
|
* minimum keywords in JSON Schema. And the PropertiesConstraint class provides
|
|
|
|
* support for the properties, patternProperties, and additionalProperties
|
|
|
|
* keywords.
|
|
|
|
*
|
|
|
|
* This is the JSON Schema representation of the Schema that will be created:
|
|
|
|
*
|
|
|
|
* {
|
|
|
|
* "properties": {
|
|
|
|
* "category": {
|
|
|
|
* "enum": [
|
|
|
|
* "album",
|
|
|
|
* "book",
|
|
|
|
* "other",
|
|
|
|
* "video"
|
|
|
|
* ]
|
|
|
|
* },
|
|
|
|
* "description": {
|
|
|
|
* "type": "string"
|
|
|
|
* },
|
|
|
|
* "price": {
|
|
|
|
* "exclusiveMinimum": true,
|
|
|
|
* "minimum": 0.0,
|
|
|
|
* "type": "number"
|
|
|
|
* },
|
|
|
|
* "title": {
|
|
|
|
* "maxLength": 200,
|
|
|
|
* "minLength": 1,
|
|
|
|
* "type": "string"
|
|
|
|
* }
|
|
|
|
* },
|
|
|
|
* "required": [
|
|
|
|
* "category",
|
|
|
|
* "price",
|
|
|
|
* "title"
|
|
|
|
* ],
|
|
|
|
* "type": "object"
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <fstream>
|
|
|
|
#include <iostream>
|
|
|
|
#include <stdexcept>
|
|
|
|
|
|
|
|
#include <valijson/adapters/rapidjson_adapter.hpp>
|
|
|
|
#include <valijson/constraints/concrete_constraints.hpp>
|
|
|
|
#include <valijson/utils/rapidjson_utils.hpp>
|
|
|
|
#include <valijson/schema.hpp>
|
|
|
|
#include <valijson/validation_results.hpp>
|
|
|
|
#include <valijson/validator.hpp>
|
|
|
|
|
|
|
|
using std::cerr;
|
|
|
|
using std::endl;
|
|
|
|
|
|
|
|
using valijson::Schema;
|
2015-12-23 04:34:04 +01:00
|
|
|
using valijson::Subschema;
|
2013-10-29 21:51:11 +01:00
|
|
|
using valijson::Validator;
|
|
|
|
using valijson::ValidationResults;
|
|
|
|
using valijson::adapters::RapidJsonAdapter;
|
|
|
|
using valijson::adapters::RapidJsonFrozenValue;
|
|
|
|
using valijson::constraints::EnumConstraint;
|
|
|
|
using valijson::constraints::MaxLengthConstraint;
|
|
|
|
using valijson::constraints::MinimumConstraint;
|
|
|
|
using valijson::constraints::MinLengthConstraint;
|
|
|
|
using valijson::constraints::PropertiesConstraint;
|
|
|
|
using valijson::constraints::RequiredConstraint;
|
|
|
|
using valijson::constraints::TypeConstraint;
|
|
|
|
|
|
|
|
void addPropertiesConstraint(Schema &schema)
|
|
|
|
{
|
2014-02-28 23:03:39 +01:00
|
|
|
|
2016-01-08 00:21:42 +01:00
|
|
|
PropertiesConstraint propertiesConstraint;
|
2014-02-28 23:03:39 +01:00
|
|
|
|
2013-10-29 21:51:11 +01:00
|
|
|
{
|
2015-12-23 04:34:04 +01:00
|
|
|
// Prepare an enum constraint requires a document to be equal to at
|
|
|
|
// least one of a set of possible values
|
2016-01-02 00:27:52 +01:00
|
|
|
EnumConstraint constraint;
|
|
|
|
constraint.addValue(RapidJsonFrozenValue("album"));
|
|
|
|
constraint.addValue(RapidJsonFrozenValue("book"));
|
|
|
|
constraint.addValue(RapidJsonFrozenValue("other"));
|
|
|
|
constraint.addValue(RapidJsonFrozenValue("video"));
|
2015-12-23 04:34:04 +01:00
|
|
|
|
|
|
|
// Create a subschema, owned by the root schema, with a constraint
|
|
|
|
const Subschema *subschema = schema.createSubschema();
|
2016-01-02 00:27:52 +01:00
|
|
|
schema.addConstraintToSubschema(constraint, subschema);
|
2015-12-23 04:34:04 +01:00
|
|
|
|
|
|
|
// Include subschema in properties constraint
|
2016-01-08 00:21:42 +01:00
|
|
|
propertiesConstraint.addPropertySubschema("category", subschema);
|
2013-10-29 21:51:11 +01:00
|
|
|
}
|
2014-02-28 23:03:39 +01:00
|
|
|
|
2013-10-29 21:51:11 +01:00
|
|
|
{
|
|
|
|
// Create a child schema for the 'description' property that requires
|
|
|
|
// a string, but does not enforce any length constraints.
|
2015-12-23 04:34:04 +01:00
|
|
|
const Subschema *subschema = schema.createSubschema();
|
2015-12-28 23:28:22 +01:00
|
|
|
TypeConstraint typeConstraint;
|
|
|
|
typeConstraint.addNamedType(TypeConstraint::kString);
|
|
|
|
schema.addConstraintToSubschema(typeConstraint, subschema);
|
2015-12-23 04:34:04 +01:00
|
|
|
|
|
|
|
// Include subschema in properties constraint
|
2016-01-08 00:21:42 +01:00
|
|
|
propertiesConstraint.addPropertySubschema("description", subschema);
|
2013-10-29 21:51:11 +01:00
|
|
|
}
|
2014-02-28 23:03:39 +01:00
|
|
|
|
2013-10-29 21:51:11 +01:00
|
|
|
{
|
|
|
|
// Create a child schema for the 'price' property, that requires a
|
|
|
|
// number with a value greater than zero.
|
2015-12-23 04:34:04 +01:00
|
|
|
const Subschema *subschema = schema.createSubschema();
|
2016-01-10 00:11:38 +01:00
|
|
|
MinimumConstraint minimumConstraint;
|
|
|
|
minimumConstraint.setMinimum(0.0);
|
|
|
|
minimumConstraint.setExclusiveMinimum(true);
|
|
|
|
schema.addConstraintToSubschema(minimumConstraint, subschema);
|
2015-12-28 23:28:22 +01:00
|
|
|
TypeConstraint typeConstraint;
|
|
|
|
typeConstraint.addNamedType(TypeConstraint::kNumber);
|
|
|
|
schema.addConstraintToSubschema(typeConstraint, subschema);
|
2015-12-23 04:34:04 +01:00
|
|
|
|
|
|
|
// Include subschema in properties constraint
|
2016-01-08 00:21:42 +01:00
|
|
|
propertiesConstraint.addPropertySubschema("price", subschema);
|
2013-10-29 21:51:11 +01:00
|
|
|
}
|
2014-02-28 23:03:39 +01:00
|
|
|
|
2013-10-29 21:51:11 +01:00
|
|
|
{
|
|
|
|
// Create a child schema for the 'title' property that requires a string
|
|
|
|
// that is between 1 and 200 characters in length.
|
2015-12-23 04:34:04 +01:00
|
|
|
const Subschema *subschema = schema.createSubschema();
|
2016-01-11 11:37:12 +01:00
|
|
|
MaxLengthConstraint maxLengthConstraint;
|
|
|
|
maxLengthConstraint.setMaxLength(200);
|
|
|
|
schema.addConstraintToSubschema(maxLengthConstraint, subschema);
|
|
|
|
MinLengthConstraint minLengthConstraint;
|
|
|
|
minLengthConstraint.setMinLength(0);
|
|
|
|
schema.addConstraintToSubschema(minLengthConstraint, subschema);
|
2015-12-28 23:28:22 +01:00
|
|
|
TypeConstraint typeConstraint;
|
|
|
|
typeConstraint.addNamedType(TypeConstraint::kString);
|
|
|
|
schema.addConstraintToSubschema(typeConstraint, subschema);
|
2015-12-23 04:34:04 +01:00
|
|
|
|
|
|
|
// Include subschema in properties constraint
|
2016-01-08 00:21:42 +01:00
|
|
|
propertiesConstraint.addPropertySubschema("title", subschema);
|
2013-10-29 21:51:11 +01:00
|
|
|
}
|
|
|
|
|
2016-01-08 00:21:42 +01:00
|
|
|
// Add a PropertiesConstraint to the root schema
|
|
|
|
schema.addConstraint(propertiesConstraint);
|
2013-10-29 21:51:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void addRequiredConstraint(Schema &schema)
|
|
|
|
{
|
|
|
|
// Add a RequiredConstraint to the schema, specifying that the category,
|
|
|
|
// price, and title properties must be present.
|
2015-12-29 21:58:54 +01:00
|
|
|
RequiredConstraint constraint;
|
|
|
|
constraint.addRequiredProperty("category");
|
|
|
|
constraint.addRequiredProperty("price");
|
|
|
|
constraint.addRequiredProperty("title");
|
|
|
|
schema.addConstraint(constraint);
|
2013-10-29 21:51:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void addTypeConstraint(Schema &schema)
|
|
|
|
{
|
2014-02-28 23:03:39 +01:00
|
|
|
// Add a TypeConstraint to the schema, specifying that the root of the
|
2013-10-29 21:51:11 +01:00
|
|
|
// document must be an object.
|
2015-12-28 23:28:22 +01:00
|
|
|
TypeConstraint typeConstraint;
|
|
|
|
typeConstraint.addNamedType(TypeConstraint::kObject);
|
|
|
|
schema.addConstraint(typeConstraint);
|
2013-10-29 21:51:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char *argv[])
|
|
|
|
{
|
2015-03-15 05:38:40 +01:00
|
|
|
if (argc != 2) {
|
|
|
|
cerr << "Usage:" << endl;
|
|
|
|
cerr << " ./custom_schema <document>" << endl;
|
|
|
|
cerr << endl;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2013-10-29 21:51:11 +01:00
|
|
|
// Load the document that is to be validated
|
|
|
|
rapidjson::Document targetDocument;
|
|
|
|
if (!valijson::utils::loadDocument(argv[1], targetDocument)) {
|
|
|
|
cerr << "Failed to load target document." << endl;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Populate a schema
|
|
|
|
Schema schema;
|
|
|
|
addPropertiesConstraint(schema);
|
|
|
|
addRequiredConstraint(schema);
|
|
|
|
addTypeConstraint(schema);
|
2014-02-28 23:03:39 +01:00
|
|
|
|
2013-10-29 21:51:11 +01:00
|
|
|
// Perform validation
|
2015-12-23 04:34:04 +01:00
|
|
|
Validator validator;
|
2013-10-29 21:51:11 +01:00
|
|
|
ValidationResults results;
|
|
|
|
RapidJsonAdapter targetDocumentAdapter(targetDocument);
|
2015-12-23 04:34:04 +01:00
|
|
|
if (!validator.validate(schema, targetDocumentAdapter, &results)) {
|
2013-10-29 21:51:11 +01:00
|
|
|
std::cerr << "Validation failed." << endl;
|
|
|
|
ValidationResults::Error error;
|
|
|
|
unsigned int errorNum = 1;
|
|
|
|
while (results.popError(error)) {
|
2015-03-15 05:38:40 +01:00
|
|
|
cerr << "Error #" << errorNum << std::endl;
|
|
|
|
cerr << " ";
|
2016-08-10 17:22:06 +02:00
|
|
|
for (const std::string &contextElement : error.context) {
|
2015-03-15 05:38:40 +01:00
|
|
|
cerr << contextElement << " ";
|
|
|
|
}
|
|
|
|
cerr << endl;
|
|
|
|
cerr << " - " << error.description << endl;
|
2013-10-29 21:51:11 +01:00
|
|
|
++errorNum;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2016-08-01 22:09:31 +02:00
|
|
|
}
|