From cdabbe5549fec4b60fa2c96359bd1e680c02bfce Mon Sep 17 00:00:00 2001 From: Tristan Penman Date: Sun, 13 Dec 2015 13:09:12 +1100 Subject: [PATCH] Update SchemaParser to pass optional resolution scope with recursive fn calls --- include/valijson/schema_parser.hpp | 139 +++++++++++++++++------------ 1 file changed, 80 insertions(+), 59 deletions(-) diff --git a/include/valijson/schema_parser.hpp b/include/valijson/schema_parser.hpp index d664721..784081e 100644 --- a/include/valijson/schema_parser.hpp +++ b/include/valijson/schema_parser.hpp @@ -94,6 +94,7 @@ private: * document * @param node Reference to node to parse * @param schema Reference to Schema to populate + * @param currentScope URI for current resolution scope * @param fetchDoc Function to fetch remote JSON documents (optional) * @param parentSchema Optional pointer to the parent schema, used to * support required keyword in Draft 3. @@ -105,6 +106,7 @@ private: const AdapterType &rootNode, const AdapterType &node, Schema &schema, + boost::optional currentScope, boost::optional::Type> fetchDoc = boost::none, Schema *parentSchema = NULL, @@ -127,7 +129,7 @@ private: } const std::string &jsonRef = itr->second.asString(); populateSchemaUsingJsonReference(jsonRef, rootNode, node, - schema, fetchDoc, parentSchema, ownName); + schema, currentScope, fetchDoc, parentSchema, ownName); return; } } @@ -143,17 +145,17 @@ private: if ((itr = object.find("allOf")) != object.end()) { schema.addConstraint(makeAllOfConstraint(rootNode, itr->second, - fetchDoc)); + currentScope, fetchDoc)); } if ((itr = object.find("anyOf")) != object.end()) { schema.addConstraint(makeAnyOfConstraint(rootNode, itr->second, - fetchDoc)); + currentScope, fetchDoc)); } if ((itr = object.find("dependencies")) != object.end()) { schema.addConstraint(makeDependenciesConstraint(rootNode, - itr->second, fetchDoc)); + itr->second, currentScope, fetchDoc)); } if ((itr = object.find("description")) != object.end()) { @@ -188,7 +190,7 @@ private: schema.addConstraint(makeItemsConstraint(rootNode, itemsItr != object.end() ? &itemsItr->second : NULL, additionalitemsItr != object.end() ? &additionalitemsItr->second : NULL, - fetchDoc)); + currentScope, fetchDoc)); } } @@ -248,12 +250,12 @@ private: if ((itr = object.find("not")) != object.end()) { schema.addConstraint(makeNotConstraint(rootNode, itr->second, - fetchDoc)); + currentScope, fetchDoc)); } if ((itr = object.find("oneOf")) != object.end()) { schema.addConstraint(makeOneOfConstraint(rootNode, itr->second, - fetchDoc)); + currentScope, fetchDoc)); } if ((itr = object.find("pattern")) != object.end()) { @@ -274,7 +276,7 @@ private: propertiesItr != object.end() ? &propertiesItr->second : NULL, patternPropertiesItr != object.end() ? &patternPropertiesItr->second : NULL, additionalPropertiesItr != object.end() ? &additionalPropertiesItr->second : NULL, - fetchDoc, &schema)); + currentScope, fetchDoc, &schema)); } } @@ -303,7 +305,7 @@ private: if ((itr = object.find("type")) != object.end()) { schema.addConstraint(makeTypeConstraint(rootNode, itr->second, - fetchDoc)); + currentScope, fetchDoc)); } if ((itr = object.find("uniqueItems")) != object.end()) { @@ -326,6 +328,7 @@ private: * document; used for recursive parsing of schemas * @param node Reference to node to parse * @param schema Reference to Schema to populate + * @param currentScope URI for current resolution scope * @param fetchDoc Function to fetch remote JSON documents (optional) * @param parentSchema Optional pointer to the parent schema, used to * support required keyword in Draft 3. @@ -338,6 +341,7 @@ private: const AdapterType &rootNode, const AdapterType &node, Schema &schema, + boost::optional currentScope, boost::optional::Type> fetchDoc, Schema *parentSchema = NULL, @@ -375,27 +379,28 @@ private: *docPtr, jsonPointer); // Resolve reference against retrieved document - populateSchema(ref, schema, fetchDoc, parentSchema, - ownName); + populateSchema(ref, ref, schema, currentScope, + fetchDoc, parentSchema, ownName); } else { const AdapterType &ref = internal::json_pointer::resolveJsonPointer( rootNode, jsonPointer); // Resolve reference against current document - populateSchema(rootNode, ref, schema, fetchDoc, - parentSchema, ownName); + populateSchema(rootNode, ref, schema, currentScope, + fetchDoc, parentSchema, ownName); } } /** * @brief Make a new AllOfConstraint object * - * @param rootNode Reference to the node from which JSON References - * will be resolved when they refer to the current - * document; used for recursive parsing of schemas - * @param node JSON node containing an array of child schemas - * @param fetchDoc Function to fetch remote JSON documents (optional) + * @param rootNode Reference to the node from which JSON References + * will be resolved when they refer to the current + * document; used for recursive parsing of schemas + * @param node JSON node containing an array of child schemas + * @param currentScope URI for current resolution scope + * @param fetchDoc Function to fetch remote JSON documents (optional) * * @return pointer to a new AllOfConstraint object that belongs to the * caller @@ -404,6 +409,7 @@ private: constraints::AllOfConstraint* makeAllOfConstraint( const AdapterType &rootNode, const AdapterType &node, + boost::optional currentScope, boost::optional::Type > fetchDoc) { if (!node.maybeArray()) { @@ -415,7 +421,7 @@ private: if (schemaNode.maybeObject()) { childSchemas.push_back(new Schema); populateSchema(rootNode, schemaNode, - childSchemas.back(), fetchDoc); + childSchemas.back(), currentScope, fetchDoc); } else { throw std::runtime_error("Expected array element to be an object value in 'allOf' constraint."); } @@ -428,11 +434,12 @@ private: /** * @brief Make a new AnyOfConstraint object * - * @param rootNode Reference to the node from which JSON References - * will be resolved when they refer to the current - * document; used for recursive parsing of schemas - * @param node JSON node containing an array of child schemas - * @param fetchDoc Function to fetch remote JSON documents (optional) + * @param rootNode Reference to the node from which JSON References + * will be resolved when they refer to the current + * document; used for recursive parsing of schemas + * @param node JSON node containing an array of child schemas + * @param currentScope URI for current resolution scope + * @param fetchDoc Function to fetch remote JSON documents (optional) * * @return pointer to a new AnyOfConstraint object that belongs to the * caller @@ -441,6 +448,7 @@ private: constraints::AnyOfConstraint* makeAnyOfConstraint( const AdapterType &rootNode, const AdapterType &node, + boost::optional currentScope, boost::optional::Type > fetchDoc) { if (!node.maybeArray()) { @@ -452,7 +460,7 @@ private: if (schemaNode.maybeObject()) { childSchemas.push_back(new Schema); populateSchema(rootNode, schemaNode, - childSchemas.back(), fetchDoc); + childSchemas.back(), currentScope, fetchDoc); } else { throw std::runtime_error("Expected array element to be an object value in 'anyOf' constraint."); } @@ -482,12 +490,13 @@ private: * If the format of any part of the the dependency node does not match one * of these formats, an exception will be thrown. * - * @param rootNode Reference to the node from which JSON References - * will be resolved when they refer to the current - * document; used for recursive parsing of schemas - * @param node JSON node containing an object that defines a mapping - * of properties to their dependencies. - * @param fetchDoc Function to fetch remote JSON documents (optional) + * @param rootNode Reference to the node from which JSON References + * will be resolved when they refer to the current + * document; used for recursive parsing of schemas + * @param node JSON node containing an object that defines a + * mapping of properties to their dependencies. + * @param currentScope URI for current resolution scope + * @param fetchDoc Function to fetch remote JSON documents (optional) * * @return pointer to a new DependencyConstraint that belongs to the * caller @@ -496,6 +505,7 @@ private: constraints::DependenciesConstraint* makeDependenciesConstraint( const AdapterType &rootNode, const AdapterType &node, + boost::optional currentScope, boost::optional::Type > fetchDoc) { @@ -538,7 +548,7 @@ private: // Parse dependent subschema Schema &childSchema = pdsm[member.first]; populateSchema(rootNode, member.second, - childSchema, fetchDoc); + childSchema, currentScope, fetchDoc); // If we're supposed to be parsing a Draft3 schema, then the value // of the dependency mapping can also be a string containing the @@ -592,6 +602,7 @@ private: * @param additionalItems Optional pointer to a JSON node containing * an additional properties schema or a boolean * value. + * @param currentScope URI for current resolution scope * @param fetchDoc Function to fetch remote JSON documents * (optional) * @@ -602,6 +613,7 @@ private: const AdapterType &rootNode, const AdapterType *items, const AdapterType *additionalItems, + boost::optional currentScope, boost::optional::Type > fetchDoc) { @@ -622,7 +634,7 @@ private: // used to validate additional array items. additionalItemsSchema.reset(new Schema()); populateSchema(rootNode, *additionalItems, - *additionalItemsSchema, fetchDoc); + *additionalItemsSchema, currentScope, fetchDoc); } else { // Any other format for the additionalItems property will result // in an exception being thrown. @@ -650,7 +662,7 @@ private: itemSchemas.push_back(new Schema()); Schema &childSchema = itemSchemas.back(); populateSchema(rootNode, v, childSchema, - fetchDoc); + currentScope, fetchDoc); } // Create an ItemsConstraint object using the appropriate @@ -668,7 +680,7 @@ private: // additionalItems constraint will be ignored. Schema childSchema; populateSchema(rootNode, *items, childSchema, - fetchDoc); + currentScope, fetchDoc); if (additionalItemsSchema) { return new constraints::ItemsConstraint(childSchema, *additionalItemsSchema); } else { @@ -934,10 +946,12 @@ private: /** * @brief Make a new NotConstraint object * - * @param rootNode Reference to the node from which JSON References - * will be resolved when they refer to the current - * document; used for recursive parsing of schemas - * @param node JSON node containing a schema + * @param rootNode Reference to the node from which JSON References + * will be resolved when they refer to the current + * document; used for recursive parsing of schemas + * @param node JSON node containing a schema + * @param currentScope URI for current resolution scope + * @param fetchDoc Function to fetch remote JSON documents (optional) * * @return pointer to a new NotConstraint object that belongs to the caller */ @@ -945,11 +959,13 @@ private: constraints::NotConstraint* makeNotConstraint( const AdapterType &rootNode, const AdapterType &node, + boost::optional currentScope, boost::optional::Type > fetchDoc) { if (node.maybeObject()) { Schema childSchema; - populateSchema(rootNode, node, childSchema, fetchDoc); + populateSchema(rootNode, node, childSchema, + currentScope, fetchDoc); return new constraints::NotConstraint(childSchema); } @@ -959,12 +975,12 @@ private: /** * @brief Make a new OneOfConstraint object * - * @param rootNode Reference to the node from which JSON References - * will be resolved when they refer to the current - * document; used for recursive parsing of schemas - * @param node JSON node containing an array of child schemas - * @param fetchDoc Function to fetch remote JSON documents (optional) - + * @param rootNode Reference to the node from which JSON References + * will be resolved when they refer to the current + * document; used for recursive parsing of schemas + * @param node JSON node containing an array of child schemas + * @param currentScope URI for current resolution scope + * @param fetchDoc Function to fetch remote JSON documents (optional) * * @return pointer to a new OneOfConstraint that belongs to the caller */ @@ -972,6 +988,7 @@ private: constraints::OneOfConstraint* makeOneOfConstraint( const AdapterType &rootNode, const AdapterType &node, + boost::optional currentScope, boost::optional::Type > fetchDoc) { @@ -979,7 +996,7 @@ private: BOOST_FOREACH ( const AdapterType schemaNode, node.getArray() ) { childSchemas.push_back(new Schema); populateSchema(rootNode, schemaNode, - childSchemas.back(), fetchDoc); + childSchemas.back(), currentScope, fetchDoc); } /// @todo: bypass deep copy of the child schemas @@ -1017,6 +1034,7 @@ private: * @param additionalProperties Optional pointer to a JSON node containing * an additional properties schema or a * boolean value. + * @param currentScope URI for current resolution scope * @param fetchDoc Function to fetch remote JSON documents * (optional) * @param parentSchema Optional pointer to the Schema of the @@ -1031,6 +1049,7 @@ private: const AdapterType *properties, const AdapterType *patternProperties, const AdapterType *additionalProperties, + boost::optional currentScope, boost::optional::Type > fetchDoc, Schema *parentSchema) @@ -1046,8 +1065,8 @@ private: const std::string &propertyName = m.first; Schema &childSchema = propertySchemas[propertyName]; populateSchema( - rootNode, m.second, childSchema, // Required - fetchDoc, parentSchema, &propertyName); // Optional + rootNode, m.second, childSchema, currentScope, fetchDoc, + parentSchema, &propertyName); } } @@ -1059,8 +1078,8 @@ private: const std::string &propertyName = m.first; Schema &childSchema = patternPropertySchemas[propertyName]; populateSchema( - rootNode, m.second, childSchema, // Required - fetchDoc, parentSchema, &propertyName); // Optional + rootNode, m.second, childSchema, currentScope, fetchDoc, + parentSchema, &propertyName); } } @@ -1086,7 +1105,7 @@ private: // a child schema. additionalPropertiesSchema.reset(new Schema()); populateSchema(rootNode, *additionalProperties, - *additionalPropertiesSchema, fetchDoc); + *additionalPropertiesSchema, currentScope, fetchDoc); } else { // All other types are invalid throw std::runtime_error("Invalid type for 'additionalProperties' constraint."); @@ -1168,11 +1187,12 @@ private: /** * @brief Make a new TypeConstraint object * - * @param rootNode Reference to the node from which JSON References - * will be resolved when they refer to the current - * document; used for recursive parsing of schemas - * @param node Node containing the name of a JSON type - * @param fetchDoc Function to fetch remote JSON documents (optional) + * @param rootNode Reference to the node from which JSON References + * will be resolved when they refer to the current + * document; used for recursive parsing of schemas + * @param node Node containing the name of a JSON type + * @param currentScope URI for current resolution scope + * @param fetchDoc Function to fetch remote JSON documents (optional) * * @return pointer to a new TypeConstraint object. @@ -1181,6 +1201,7 @@ private: constraints::TypeConstraint* makeTypeConstraint( const AdapterType &rootNode, const AdapterType &node, + boost::optional currentScope, boost::optional::Type > fetchDoc) { @@ -1208,7 +1229,7 @@ private: // Schema! schemas.push_back(new Schema()); populateSchema(rootNode, v, schemas.back(), - fetchDoc); + currentScope, fetchDoc); } else { throw std::runtime_error("Type name should be a string."); } @@ -1216,7 +1237,7 @@ private: } else if (node.isObject() && version == kDraft3) { schemas.push_back(new Schema()); populateSchema(rootNode, node, schemas.back(), - fetchDoc); + currentScope, fetchDoc); } else { throw std::runtime_error("Type name should be a string."); }