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 <rapidjson/document.h>
|
|
|
|
|
|
|
|
#include <valijson/adapters/rapidjson_adapter.hpp>
|
|
|
|
#include <valijson/constraints/concrete_constraints.hpp>
|
|
|
|
#include <valijson/utils/rapidjson_utils.hpp>
|
|
|
|
#include <valijson/schema.hpp>
|
|
|
|
#include <valijson/schema_parser.hpp>
|
|
|
|
#include <valijson/validation_results.hpp>
|
|
|
|
#include <valijson/validator.hpp>
|
|
|
|
|
|
|
|
using std::cerr;
|
|
|
|
using std::endl;
|
|
|
|
|
|
|
|
using valijson::Schema;
|
|
|
|
using valijson::SchemaParser;
|
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
|
|
|
|
2013-10-29 21:51:11 +01:00
|
|
|
PropertiesConstraint::PropertySchemaMap propertySchemaMap;
|
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
|
2013-10-29 21:51:11 +01:00
|
|
|
EnumConstraint::Values enumConstraintValues;
|
|
|
|
enumConstraintValues.push_back(new RapidJsonFrozenValue("album"));
|
|
|
|
enumConstraintValues.push_back(new RapidJsonFrozenValue("book"));
|
|
|
|
enumConstraintValues.push_back(new RapidJsonFrozenValue("other"));
|
|
|
|
enumConstraintValues.push_back(new 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();
|
|
|
|
schema.addConstraintToSubschema(EnumConstraint(enumConstraintValues),
|
|
|
|
subschema);
|
|
|
|
|
|
|
|
// Include subschema in properties constraint
|
|
|
|
propertySchemaMap["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
|
|
|
|
propertySchemaMap["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();
|
|
|
|
schema.addConstraintToSubschema(MinimumConstraint(0.0, true), 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
|
|
|
|
propertySchemaMap["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();
|
|
|
|
schema.addConstraintToSubschema(MaxLengthConstraint(200), subschema);
|
|
|
|
schema.addConstraintToSubschema(MinLengthConstraint(1), 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
|
|
|
|
propertySchemaMap["title"] = subschema;
|
2013-10-29 21:51:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Add a PropertiesConstraint to the schema, with the properties defined
|
2015-12-23 04:34:04 +01:00
|
|
|
// above, no pattern properties or additional property schemas
|
|
|
|
schema.addConstraint(PropertiesConstraint(propertySchemaMap));
|
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.
|
|
|
|
RequiredConstraint::RequiredProperties requiredProperties;
|
|
|
|
requiredProperties.insert("category");
|
|
|
|
requiredProperties.insert("price");
|
|
|
|
requiredProperties.insert("title");
|
2015-12-23 22:03:02 +01:00
|
|
|
schema.addConstraint(RequiredConstraint(requiredProperties));
|
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 << " ";
|
|
|
|
BOOST_FOREACH( const std::string contextElement, error.context ) {
|
|
|
|
cerr << contextElement << " ";
|
|
|
|
}
|
|
|
|
cerr << endl;
|
|
|
|
cerr << " - " << error.description << endl;
|
2013-10-29 21:51:11 +01:00
|
|
|
++errorNum;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|