diff --git a/src/ujson/Schema.cpp b/src/ujson/Schema.cpp
index 0f87f19..2039677 100644
--- a/src/ujson/Schema.cpp
+++ b/src/ujson/Schema.cpp
@@ -16,7 +16,9 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
+#include
#include
+#include
#include
#include
@@ -73,12 +75,11 @@ namespace ujson {
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
- Schema::Schema (jvalue& schema)
- : root_schema (schema)
+ Schema::Schema (jvalue& root_instance)
+ : root_schema (root_instance)
{
}
-
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
Schema::result_t Schema::validate (jvalue& instance)
@@ -86,6 +87,38 @@ namespace ujson {
return validate_impl (root_schema, instance);
}
+
+ //--------------------------------------------------------------------------
+ //--------------------------------------------------------------------------
+ bool Schema::add_ref_schema (const Schema& schema)
+ {
+ auto& id = find_jvalue (const_cast(schema.root_schema), "/$id");
+ if (id.type() != j_string)
+ return false;
+
+ ref_schemas.emplace (id.str(), Schema(schema));
+ ref_cache.clear ();
+ return true;
+ }
+
+
+ //--------------------------------------------------------------------------
+ //--------------------------------------------------------------------------
+ void Schema::del_ref_schema (const std::string& id)
+ {
+ ref_schemas.erase (id);
+ ref_cache.clear ();
+ }
+
+
+ //--------------------------------------------------------------------------
+ //--------------------------------------------------------------------------
+ jvalue& Schema::root ()
+ {
+ return root_schema;
+ }
+
+
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
static bool is_schema_type (jvalue& schema)
@@ -96,24 +129,51 @@ namespace ujson {
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
- jvalue* Schema::get_ref_schema (const std::string& ref)
+ Schema::result_t Schema::handle_ref (const std::string& ref, jvalue& instance)
{
- jvalue* schema = nullptr;
- std::stringstream ss (ref);
- std::string part;
- std::vector parts;
- std::getline(ss, part, '/');
- if (part == "#") {
- while (std::getline(ss, part, '/')) {
- if (schema == nullptr)
- schema = &(root_schema.get(part));
- else
- schema = &(schema->get(part));
- if (schema->type() == j_invalid)
- break;
+ auto entry = ref_cache.find (ref);
+ if (entry != ref_cache.end()) {
+ Schema& ref_root = entry->second.first;
+ jvalue& ref_schema = entry->second.second;
+ return ref_root.validate_impl (ref_schema, instance);
+ }
+
+ std::string id;
+ std::string pointer;
+
+ auto pos = ref.find ("#");
+ if (pos == std::string::npos) {
+ pointer = ref;
+ }else{
+ id = ref.substr (0, pos);
+ pointer = ref.substr (pos+1);
+ }
+ pointer.insert (0, 1, '/'); // Make sure the pointer starts with /
+
+ if (id.empty()) {
+ // Reference to pointer in this schema
+ auto& ref_schema = find_jvalue (root_schema, pointer);
+ if (ref_schema.valid()) {
+ ref_cache.emplace (ref,
+ std::make_pair(std::reference_wrapper(*this),
+ std::reference_wrapper(ref_schema)));
+ }
+ return validate_impl (ref_schema, instance);
+ }else{
+ // Reference to pointer in other schema
+ auto entry = ref_schemas.find (id);
+ if (entry == ref_schemas.end()) {
+ return err_schema;
}
+ auto& ref_root = entry->second;
+ auto& ref_schema = find_jvalue (ref_root.root_schema, pointer);
+ if (ref_schema.valid()) {
+ ref_cache.emplace (ref,
+ std::make_pair(std::reference_wrapper(ref_root),
+ std::reference_wrapper(ref_schema)));
+ }
+ return ref_root.validate_impl (ref_schema, instance);
}
- return schema;
}
@@ -141,14 +201,8 @@ namespace ujson {
// Handle keyword "$ref" first
//
auto& ref = schema.get("$ref");
- if (ref.type() != j_invalid) {
- jvalue* ref_schema = get_ref_schema (ref.str());
- if (!ref_schema)
- return err_schema;
- vdata.result = validate_impl (*ref_schema, instance);
- if (vdata.result != valid)
- return vdata.result;
- }
+ if (ref.type() != j_invalid)
+ return handle_ref (ref.str(), instance);
// Handle the schema keywords
//
@@ -340,11 +394,6 @@ namespace ujson {
}
}
- //
- // Validation
- //
-
-
if (vdata.result != valid)
return vdata.result;
}
diff --git a/src/ujson/Schema.hpp b/src/ujson/Schema.hpp
index b07731f..b7727d2 100644
--- a/src/ujson/Schema.hpp
+++ b/src/ujson/Schema.hpp
@@ -40,20 +40,37 @@ namespace ujson {
};
/**
- * Constructor.
+ * Default constructor.
*/
- Schema (jvalue& schema);
+ Schema () = default;
/**
- * Destructor.
+ * Constructor.
*/
- ~Schema () = default;
+ Schema (jvalue& root_instance);
/**
* @return Schema::valid on success.
*/
result_t validate (jvalue& instance);
+ /**
+ * Add a schema that this schema mey refer to.
+ */
+ bool add_ref_schema (const Schema& schema);
+
+ /**
+ * Remove a schema that this schema mey refer to.
+ * @param id The id of the schema to remove.
+ */
+ void del_ref_schema (const std::string& id);
+
+ /**
+ * Return the root schema instance.
+ */
+ jvalue& root ();
+
+
private:
struct vdata_t {
jvalue& schema;
@@ -74,9 +91,15 @@ namespace ujson {
};
jvalue root_schema;
- jvalue* get_ref_schema (const std::string& ref);
+ std::map ref_schemas;
+ std::map,
+ std::reference_wrapper>> ref_cache;
+
result_t validate_impl (jvalue& schema, jvalue& instance);
+ result_t handle_ref (const std::string& ref, jvalue& instance);
+
// Core - all types
void handle_allOf (vdata_t& vdata, jvalue& value);
void handle_anyOf (vdata_t& vdata, jvalue& value);
diff --git a/utils/ujson-verify.cpp b/utils/ujson-verify.cpp
index c8e1004..3e3a243 100644
--- a/utils/ujson-verify.cpp
+++ b/utils/ujson-verify.cpp
@@ -41,6 +41,7 @@ struct appargs_t {
bool quiet;
std::vector files;
std::string schema_file;
+ std::vector ref_schema_files;
appargs_t() {
strict = true;
@@ -59,10 +60,14 @@ static void print_usage_and_exit (std::ostream& out, int exit_code)
<< "Usage: " << prog_name << " [OPTIONS] [FILE...]" << endl
<< endl
<< "Options:" <