diff --git a/include/valijson/internal/json_reference.hpp b/include/valijson/internal/json_reference.hpp index 5702235..d06538a 100644 --- a/include/valijson/internal/json_reference.hpp +++ b/include/valijson/internal/json_reference.hpp @@ -41,11 +41,10 @@ namespace json_reference { * * @param jsonRef JSON Reference to extract from * - * @return string containing JSON Pointer - * - * @throw std::runtime_error if the string does not contain a JSON Pointer + * @return Optional string containing JSON Pointer */ - inline std::string getJsonReferencePointer(const std::string &jsonRef) + inline boost::optional getJsonReferencePointer( + const std::string &jsonRef) { // Attempt to extract JSON Pointer if '#' character is present. Note // that a valid pointer would contain at least a leading forward @@ -55,10 +54,10 @@ namespace json_reference { return jsonRef.substr(ptrPos + 1); } - throw std::runtime_error( - "JSON Reference value does not contain a valid JSON Pointer"); + return boost::none; } + } // namespace json_reference } // namespace internal } // namespace valijson diff --git a/include/valijson/schema_parser.hpp b/include/valijson/schema_parser.hpp index b445164..5274d8b 100644 --- a/include/valijson/schema_parser.hpp +++ b/include/valijson/schema_parser.hpp @@ -551,16 +551,26 @@ private: const typename AdapterType::Object object = node.asObject(); typename AdapterType::Object::const_iterator itr(object.end()); - if ((itr = object.find("id")) != object.end()) { - if (itr->second.maybeString()) { - rootSchema.setSubschemaId(&subschema, itr->second.asString()); + // Check for 'id' attribute and update current scope + boost::optional updatedScope; + if ((itr = object.find("id")) != object.end() && + itr->second.maybeString()) { + const std::string id = itr->second.asString(); + rootSchema.setSubschemaId(&subschema, itr->second.asString()); + if (!currentScope || internal::uri::isUriAbsolute(id)) { + updatedScope = id; + } else { + updatedScope = internal::uri::resolveRelativeUri( + *currentScope, id); } + } else { + updatedScope = currentScope; } if ((itr = object.find("allOf")) != object.end()) { rootSchema.addConstraintToSubschema( makeAllOfConstraint(rootSchema, rootNode, itr->second, - currentScope, nodePath + "/allOf", fetchDoc, + updatedScope, nodePath + "/allOf", fetchDoc, docCache, schemaCache), &subschema); } @@ -568,7 +578,7 @@ private: if ((itr = object.find("anyOf")) != object.end()) { rootSchema.addConstraintToSubschema( makeAnyOfConstraint(rootSchema, rootNode, itr->second, - currentScope, nodePath + "/anyOf", fetchDoc, + updatedScope, nodePath + "/anyOf", fetchDoc, docCache, schemaCache), &subschema); } @@ -576,7 +586,7 @@ private: if ((itr = object.find("dependencies")) != object.end()) { rootSchema.addConstraintToSubschema( makeDependenciesConstraint(rootSchema, rootNode, - itr->second, currentScope, + itr->second, updatedScope, nodePath + "/dependencies", fetchDoc, docCache, schemaCache), &subschema); @@ -625,7 +635,7 @@ private: if (!itemsItr->second.isArray()) { rootSchema.addConstraintToSubschema( makeSingularItemsConstraint(rootSchema, rootNode, - itemsItr->second, currentScope, + itemsItr->second, updatedScope, nodePath + "/items", fetchDoc, docCache, schemaCache), &subschema); @@ -639,7 +649,7 @@ private: &itemsItr->second : NULL, additionalItemsItr != object.end() ? &additionalItemsItr->second : NULL, - currentScope, nodePath + "/items", + updatedScope, nodePath + "/items", nodePath + "/additionalItems", fetchDoc, docCache, schemaCache), &subschema); @@ -734,7 +744,7 @@ private: if ((itr = object.find("not")) != object.end()) { rootSchema.addConstraintToSubschema( makeNotConstraint(rootSchema, rootNode, itr->second, - currentScope, nodePath + "/not", fetchDoc, docCache, + updatedScope, nodePath + "/not", fetchDoc, docCache, schemaCache), &subschema); } @@ -742,7 +752,7 @@ private: if ((itr = object.find("oneOf")) != object.end()) { rootSchema.addConstraintToSubschema( makeOneOfConstraint(rootSchema, rootNode, itr->second, - currentScope, nodePath + "/oneOf", fetchDoc, + updatedScope, nodePath + "/oneOf", fetchDoc, docCache, schemaCache), &subschema); } @@ -770,7 +780,7 @@ private: &patternPropertiesItr->second : NULL, additionalPropertiesItr != object.end() ? &additionalPropertiesItr->second : NULL, - currentScope, nodePath + "/properties", + updatedScope, nodePath + "/properties", nodePath + "/patternProperties", nodePath + "/additionalProperties", fetchDoc, &subschema, docCache, schemaCache), @@ -810,7 +820,7 @@ private: if ((itr = object.find("type")) != object.end()) { rootSchema.addConstraintToSubschema( makeTypeConstraint(rootSchema, rootNode, itr->second, - currentScope, nodePath + "/type", fetchDoc, + updatedScope, nodePath + "/type", fetchDoc, docCache, schemaCache), &subschema); } diff --git a/tests/test_validator.cpp b/tests/test_validator.cpp index 9c6ab67..6b9f8ce 100644 --- a/tests/test_validator.cpp +++ b/tests/test_validator.cpp @@ -263,7 +263,12 @@ TEST_F(TestValidator, Draft3_Properties) TEST_F(TestValidator, Draft3_Ref) { - processDraft3TestFile(TEST_SUITE_DIR "draft3/ref.json"); + processDraft3TestFile(TEST_SUITE_DIR "draft3/ref.json"); +} + +TEST_F(TestValidator, Draft3_RefRemote) +{ + processDraft3TestFile(TEST_SUITE_DIR "draft3/refRemote.json"); } TEST_F(TestValidator, Draft3_Required) @@ -391,6 +396,11 @@ TEST_F(TestValidator, Draft4_Ref) processDraft4TestFile(TEST_SUITE_DIR "draft4/ref.json"); } +TEST_F(TestValidator, Draft4_RefRemote) +{ + processDraft4TestFile(TEST_SUITE_DIR "draft4/refRemote.json"); +} + TEST_F(TestValidator, Draft4_Required) { processDraft4TestFile(TEST_SUITE_DIR "draft4/required.json");