diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index 4f23a79..ca14233 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -776,7 +776,6 @@ INPUT = readme.md \ doc/dom.md \ doc/sax.md \ doc/schema.md \ - doc/schema-errors.md \ doc/performance.md \ doc/internals.md \ doc/faq.md diff --git a/doc/schema-errors.md b/doc/schema-errors.md deleted file mode 100644 index f82120e..0000000 --- a/doc/schema-errors.md +++ /dev/null @@ -1,269 +0,0 @@ -# Schema violation reporting - -(Unreleased as of 2017-09-20) - -When validating an instance against a JSON Schema, -it is often desirable to report not only whether the instance is valid, -but also the ways in which it violates the schema. - -The `SchemaValidator` class -collects errors encountered during validation -into a JSON `Value`. -This error object can then be accessed as `validator.GetError()`. - -The structure of the error object is subject to change -in future versions of RapidJSON, -as there is no standard schema for violations. -The details below this point are provisional only. - -[TOC] - -# General provisions {#General} - -Validation of an instance value against a schema -produces an error value. -The error value is always an object. -An empty object `{}` indicates the instance is valid. - -* The name of each member - corresponds to the JSON Schema keyword that is violated. -* The value is either an object describing a single violation, - or an array of such objects. - -Each violation object contains two string-valued members -named `instanceRef` and `schemaRef`. -`instanceRef` contains the URI fragment serialization -of a JSON Pointer to the instance subobject -in which the violation was detected. -`schemaRef` contains the URI of the schema -and the fragment serialization of a JSON Pointer -to the subschema that was violated. - -Individual violation objects can contain other keyword-specific members. -These are detailed further. - -For example, validating this instance: - -~~~json -{"numbers": [1, 2, "3", 4, 5]} -~~~ - -against this schema: - -~~~json -{ - "type": "object", - "properties": { - "numbers": {"$ref": "numbers.schema.json"} - } -} -~~~ - -where `numbers.schema.json` refers -(via a suitable `IRemoteSchemaDocumentProvider`) -to this schema: - -~~~json -{ - "type": "array", - "items": {"type": "number"} -} -~~~ - -produces the following error object: - -~~~json -{ - "type": { - "instanceRef": "#/numbers/2", - "schemaRef": "numbers.schema.json#/items", - "expected": ["number"], - "actual": "string" - } -} -~~~ - -# Validation keywords for numbers {#numbers} - -## multipleOf {#multipleOf} - -* `expected`: required number strictly greater than 0. - The value of the `multipleOf` keyword specified in the schema. -* `actual`: required number. - The instance value. - -## maximum {#maximum} - -* `expected`: required number. - The value of the `maximum` keyword specified in the schema. -* `exclusiveMaximum`: optional boolean. - This will be true if the schema specified `"exclusiveMaximum": true`, - and will be omitted otherwise. -* `actual`: required number. - The instance value. - -## minimum {#minimum} - -* `expected`: required number. - The value of the `minimum` keyword specified in the schema. -* `exclusiveMinimum`: optional boolean. - This will be true if the schema specified `"exclusiveMinimum": true`, - and will be omitted otherwise. -* `actual`: required number. - The instance value. - -# Validation keywords for strings {#strings} - -## maxLength {#maxLength} - -* `expected`: required number greater than or equal to 0. - The value of the `maxLength` keyword specified in the schema. -* `actual`: required string. - The instance value. - -## minLength {#minLength} - -* `expected`: required number greater than or equal to 0. - The value of the `minLength` keyword specified in the schema. -* `actual`: required string. - The instance value. - -## pattern {#pattern} - -* `actual`: required string. - The instance value. - -(The expected pattern is not reported -because the internal representation in `SchemaDocument` -does not store the pattern in original string form.) - -# Validation keywords for arrays {#arrays} - -## additionalItems {#additionalItems} - -This keyword is reported -when the value of `items` schema keyword is an array, -the value of `additionalItems` is `false`, -and the instance is an array -with more items than specified in the `items` array. - -* `disallowed`: required integer greater than or equal to 0. - The index of the first item that has no corresponding schema. - -## maxItems and minItems {#maxItems} - -* `expected`: required integer greater than or equal to 0. - The value of `maxItems` (respectively, `minItems`) - specified in the schema. -* `actual`: required integer greater than or equal to 0. - Number of items in the instance array. - -## uniqueItems {#uniqueItems} - -* `duplicates`: required array - whose items are integers greater than or equal to 0. - Indices of items of the instance that are equal. - -(RapidJSON only reports the first two equal items, -for performance reasons.) - -# Validation keywords for objects - -## maxProperties and minProperties {#maxProperties} - -* `expected`: required integer greater than or equal to 0. - The value of `maxProperties` (respectively, `minProperties`) - specified in the schema. -* `actual`: required integer greater than or equal to 0. - Number of properties in the instance object. - -## required {#required} - -* `missing`: required array of one or more unique strings. - The names of properties - that are listed in the value of the `required` schema keyword - but not present in the instance object. - -## additionalProperties {#additionalProperties} - -This keyword is reported -when the schema specifies `additionalProperties: false` -and the name of a property of the instance is -neither listed in the `properties` keyword -nor matches any regular expression in the `patternProperties` keyword. - -* `disallowed`: required string. - Name of the offending property of the instance. - -(For performance reasons, -RapidJSON only reports the first such property encountered.) - -## dependencies {#dependencies} - -* `errors`: required object with one or more properties. - Names and values of its properties are described below. - -Recall that JSON Schema Draft 04 supports -*schema dependencies*, -where presence of a named *controlling* property -requires the instance object to be valid against a subschema, -and *property dependencies*, -where presence of a controlling property -requires other *dependent* properties to be also present. - -For a violated schema dependency, -`errors` will contain a property -with the name of the controlling property -and its value will be the error object -produced by validating the instance object -against the dependent schema. - -For a violated property dependency, -`errors` will contain a property -with the name of the controlling property -and its value will be an array of one or more unique strings -listing the missing dependent properties. - -# Validation keywords for any instance type {#anytypes} - -## enum {#enum} - -This keyword has no additional properties -beyond `instanceRef` and `schemaRef`. - -* The allowed values are not listed - because `SchemaDocument` does not store them in original form. -* The violating value is not reported - because it might be unwieldy. - -If you need to report these details to your users, -you can access the necessary information -by following `instanceRef` and `schemaRef`. - -## type {#type} - -* `expected`: required array of one or more unique strings, - each of which is one of the seven primitive types - defined by the JSON Schema Draft 04 Core specification. - Lists the types allowed by the `type` schema keyword. -* `actual`: required string, also one of seven primitive types. - The primitive type of the instance. - -## allOf, anyOf, and oneOf {#allOf} - -* `errors`: required array of at least one object. - There will be as many items as there are subschemas - in the `allOf`, `anyOf` or `oneOf` schema keyword, respectively. - Each item will be the error value - produced by validating the instance - against the corresponding subschema. - -For `allOf`, at least one error value will be non-empty. -For `anyOf`, all error values will be non-empty. -For `oneOf`, either all error values will be non-empty, -or more than one will be empty. - -## not {#not} - -This keyword has no additional properties -apart from `instanceRef` and `schemaRef`. diff --git a/doc/schema.md b/doc/schema.md index 29ba4f5..9d1b21a 100644 --- a/doc/schema.md +++ b/doc/schema.md @@ -8,7 +8,7 @@ RapidJSON implemented a JSON Schema validator for [JSON Schema Draft v4](http:// [TOC] -## Basic Usage +# Basic Usage {#Basic} First of all, you need to parse a JSON Schema into `Document`, and then compile the `Document` into a `SchemaDocument`. @@ -52,11 +52,11 @@ Some notes: * One `SchemaDocment` can be referenced by multiple `SchemaValidator`s. It will not be modified by `SchemaValidator`s. * A `SchemaValidator` may be reused to validate multiple documents. To run it for other documents, call `validator.Reset()` first. -## Validation during parsing/serialization +# Validation during parsing/serialization {#Fused} Unlike most JSON Schema validator implementations, RapidJSON provides a SAX-based schema validator. Therefore, you can parse a JSON from a stream while validating it on the fly. If the validator encounters a JSON value that invalidates the supplied schema, the parsing will be terminated immediately. This design is especially useful for parsing large JSON files. -### DOM parsing +## DOM parsing {#DOM} For using DOM in parsing, `Document` needs some preparation and finalizing tasks, in addition to receiving SAX events, thus it needs some work to route the reader, validator and the document. `SchemaValidatingReader` is a helper class that doing such work. @@ -97,7 +97,7 @@ if (!reader.GetParseResult()) { } ~~~ -### SAX parsing +## SAX parsing {#SAX} For using SAX in parsing, it is much simpler. If it only need to validate the JSON without further processing, it is simply: @@ -126,7 +126,7 @@ if (!reader.Parse(ss, validator)) { } ~~~ -### Serialization +## Serialization {#Serialization} It is also possible to do validation during serializing. This can ensure the result JSON is valid according to the JSON schema. @@ -144,7 +144,7 @@ if (!d.Accept(validator)) { Of course, if your application only needs SAX-style serialization, it can simply send SAX events to `SchemaValidator` instead of `Writer`. -## Remote Schema +# Remote Schema {#Remote} JSON Schema supports [`$ref` keyword](http://spacetelescope.github.io/understanding-json-schema/structuring.html), which is a [JSON pointer](doc/pointer.md) referencing to a local or remote schema. Local pointer is prefixed with `#`, while remote pointer is an relative or absolute URI. For example: @@ -168,7 +168,7 @@ MyRemoteSchemaDocumentProvider provider; SchemaDocument schema(sd, &provider); ~~~ -## Conformance +# Conformance {#Conformance} RapidJSON passed 262 out of 263 tests in [JSON Schema Test Suite](https://github.com/json-schema/JSON-Schema-Test-Suite) (Json Schema draft 4). @@ -176,7 +176,7 @@ The failed test is "changed scope ref invalid" of "change resolution scope" in ` Besides, the `format` schema keyword for string values is ignored, since it is not required by the specification. -### Regular Expression +## Regular Expression {#Regex} The schema keyword `pattern` and `patternProperties` uses regular expression to match the required pattern. @@ -211,7 +211,7 @@ RapidJSON implemented a simple NFA regular expression engine, which is used by d For C++11 compiler, it is also possible to use the `std::regex` by defining `RAPIDJSON_SCHEMA_USE_INTERNALREGEX=0` and `RAPIDJSON_SCHEMA_USE_STDREGEX=1`. If your schemas do not need `pattern` and `patternProperties`, you can set both macros to zero to disable this feature, which will reduce some code size. -## Performance +# Performance {#Performance} Most C++ JSON libraries do not yet support JSON Schema. So we tried to evaluate the performance of RapidJSON's JSON Schema validator according to [json-schema-benchmark](https://github.com/ebdrup/json-schema-benchmark), which tests 11 JavaScript libraries running on Node.js. @@ -235,3 +235,271 @@ On a Mac Book Pro (2.8 GHz Intel Core i7), the following results are collected. |[`jayschema`](https://github.com/natesilva/jayschema)|0.1%|21 (± 1.14%)| That is, RapidJSON is about 1.5x faster than the fastest JavaScript library (ajv). And 1400x faster than the slowest one. + +# Schema violation reporting {#Reporting} + +(Unreleased as of 2017-09-20) + +When validating an instance against a JSON Schema, +it is often desirable to report not only whether the instance is valid, +but also the ways in which it violates the schema. + +The `SchemaValidator` class +collects errors encountered during validation +into a JSON `Value`. +This error object can then be accessed as `validator.GetError()`. + +The structure of the error object is subject to change +in future versions of RapidJSON, +as there is no standard schema for violations. +The details below this point are provisional only. + +## General provisions {#ReportingGeneral} + +Validation of an instance value against a schema +produces an error value. +The error value is always an object. +An empty object `{}` indicates the instance is valid. + +* The name of each member + corresponds to the JSON Schema keyword that is violated. +* The value is either an object describing a single violation, + or an array of such objects. + +Each violation object contains two string-valued members +named `instanceRef` and `schemaRef`. +`instanceRef` contains the URI fragment serialization +of a JSON Pointer to the instance subobject +in which the violation was detected. +`schemaRef` contains the URI of the schema +and the fragment serialization of a JSON Pointer +to the subschema that was violated. + +Individual violation objects can contain other keyword-specific members. +These are detailed further. + +For example, validating this instance: + +~~~json +{"numbers": [1, 2, "3", 4, 5]} +~~~ + +against this schema: + +~~~json +{ + "type": "object", + "properties": { + "numbers": {"$ref": "numbers.schema.json"} + } +} +~~~ + +where `numbers.schema.json` refers +(via a suitable `IRemoteSchemaDocumentProvider`) +to this schema: + +~~~json +{ + "type": "array", + "items": {"type": "number"} +} +~~~ + +produces the following error object: + +~~~json +{ + "type": { + "instanceRef": "#/numbers/2", + "schemaRef": "numbers.schema.json#/items", + "expected": ["number"], + "actual": "string" + } +} +~~~ + +## Validation keywords for numbers {#Numbers} + +### multipleOf {#multipleof} + +* `expected`: required number strictly greater than 0. + The value of the `multipleOf` keyword specified in the schema. +* `actual`: required number. + The instance value. + +### maximum {#maximum} + +* `expected`: required number. + The value of the `maximum` keyword specified in the schema. +* `exclusiveMaximum`: optional boolean. + This will be true if the schema specified `"exclusiveMaximum": true`, + and will be omitted otherwise. +* `actual`: required number. + The instance value. + +### minimum {#minimum} + +* `expected`: required number. + The value of the `minimum` keyword specified in the schema. +* `exclusiveMinimum`: optional boolean. + This will be true if the schema specified `"exclusiveMinimum": true`, + and will be omitted otherwise. +* `actual`: required number. + The instance value. + +## Validation keywords for strings {#Strings} + +### maxLength {#maxLength} + +* `expected`: required number greater than or equal to 0. + The value of the `maxLength` keyword specified in the schema. +* `actual`: required string. + The instance value. + +### minLength {#minLength} + +* `expected`: required number greater than or equal to 0. + The value of the `minLength` keyword specified in the schema. +* `actual`: required string. + The instance value. + +### pattern {#pattern} + +* `actual`: required string. + The instance value. + +(The expected pattern is not reported +because the internal representation in `SchemaDocument` +does not store the pattern in original string form.) + +## Validation keywords for arrays {#Arrays} + +### additionalItems {#additionalItems} + +This keyword is reported +when the value of `items` schema keyword is an array, +the value of `additionalItems` is `false`, +and the instance is an array +with more items than specified in the `items` array. + +* `disallowed`: required integer greater than or equal to 0. + The index of the first item that has no corresponding schema. + +### maxItems and minItems {#maxItems-minItems} + +* `expected`: required integer greater than or equal to 0. + The value of `maxItems` (respectively, `minItems`) + specified in the schema. +* `actual`: required integer greater than or equal to 0. + Number of items in the instance array. + +### uniqueItems {#uniqueItems} + +* `duplicates`: required array + whose items are integers greater than or equal to 0. + Indices of items of the instance that are equal. + +(RapidJSON only reports the first two equal items, +for performance reasons.) + +## Validation keywords for objects + +### maxProperties and minProperties {#maxProperties-minProperties} + +* `expected`: required integer greater than or equal to 0. + The value of `maxProperties` (respectively, `minProperties`) + specified in the schema. +* `actual`: required integer greater than or equal to 0. + Number of properties in the instance object. + +### required {#required} + +* `missing`: required array of one or more unique strings. + The names of properties + that are listed in the value of the `required` schema keyword + but not present in the instance object. + +### additionalProperties {#additionalProperties} + +This keyword is reported +when the schema specifies `additionalProperties: false` +and the name of a property of the instance is +neither listed in the `properties` keyword +nor matches any regular expression in the `patternProperties` keyword. + +* `disallowed`: required string. + Name of the offending property of the instance. + +(For performance reasons, +RapidJSON only reports the first such property encountered.) + +### dependencies {#dependencies} + +* `errors`: required object with one or more properties. + Names and values of its properties are described below. + +Recall that JSON Schema Draft 04 supports +*schema dependencies*, +where presence of a named *controlling* property +requires the instance object to be valid against a subschema, +and *property dependencies*, +where presence of a controlling property +requires other *dependent* properties to be also present. + +For a violated schema dependency, +`errors` will contain a property +with the name of the controlling property +and its value will be the error object +produced by validating the instance object +against the dependent schema. + +For a violated property dependency, +`errors` will contain a property +with the name of the controlling property +and its value will be an array of one or more unique strings +listing the missing dependent properties. + +## Validation keywords for any instance type {#AnyTypes} + +### enum {#enum} + +This keyword has no additional properties +beyond `instanceRef` and `schemaRef`. + +* The allowed values are not listed + because `SchemaDocument` does not store them in original form. +* The violating value is not reported + because it might be unwieldy. + +If you need to report these details to your users, +you can access the necessary information +by following `instanceRef` and `schemaRef`. + +### type {#type} + +* `expected`: required array of one or more unique strings, + each of which is one of the seven primitive types + defined by the JSON Schema Draft 04 Core specification. + Lists the types allowed by the `type` schema keyword. +* `actual`: required string, also one of seven primitive types. + The primitive type of the instance. + +### allOf, anyOf, and oneOf {#allOf-anyOf-oneOf} + +* `errors`: required array of at least one object. + There will be as many items as there are subschemas + in the `allOf`, `anyOf` or `oneOf` schema keyword, respectively. + Each item will be the error value + produced by validating the instance + against the corresponding subschema. + +For `allOf`, at least one error value will be non-empty. +For `anyOf`, all error values will be non-empty. +For `oneOf`, either all error values will be non-empty, +or more than one will be empty. + +### not {#not} + +This keyword has no additional properties +apart from `instanceRef` and `schemaRef`.