blob: 51f521bfd595f7c51012d4b1563ef07d08d167e1 [file] [log] [blame] [edit]
/*
* Modern C++ JSON schema validator
*
* Licensed under the MIT License <http://opensource.org/licenses/MIT>.
*
* Copyright (c) 2016 Patrick Boettcher <patrick.boettcher@posteo.de>.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom
* the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
* NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
* OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NLOHMANN_JSON_SCHEMA_HPP__
#define NLOHMANN_JSON_SCHEMA_HPP__
#ifdef _WIN32
# ifdef JSON_SCHEMA_VALIDATOR_EXPORTS
# define JSON_SCHEMA_VALIDATOR_API __declspec(dllexport)
# else
# define JSON_SCHEMA_VALIDATOR_API __declspec(dllimport)
# endif
#else
# define JSON_SCHEMA_VALIDATOR_API
#endif
#include <json.hpp>
// make yourself a home - welcome to nlohmann's namespace
namespace nlohmann
{
// a class representing a JSON-pointer RFC6901
//
// examples of JSON pointers
//
// # - root of the current document
// #item - refers to the object which is identified ("id") by `item`
// in the current document
// #/path/to/element
// - refers to the element in /path/to from the root-document
//
//
// The json_pointer-class stores everything in a string, which might seem bizarre
// as parsing is done from a string to a string, but from_string() is also
// doing some formatting.
//
// TODO
// ~ and % - codec
// needs testing and clarification regarding the '#' at the beginning
class json_pointer
{
std::string str_;
void from_string(const std::string &r);
public:
json_pointer(const std::string &s = "")
{
from_string(s);
}
void append(const std::string &elem)
{
str_.append(elem);
}
const std::string &to_string() const
{
return str_;
}
};
// A class representing a JSON-URI for schemas derived from
// section 8 of JSON Schema: A Media Type for Describing JSON Documents
// draft-wright-json-schema-00
//
// New URIs can be derived from it using the derive()-method.
// This is useful for resolving refs or subschema-IDs in json-schemas.
//
// This is done implement the requirements described in section 8.2.
//
class JSON_SCHEMA_VALIDATOR_API json_uri
{
std::string urn_;
std::string proto_;
std::string hostname_;
std::string path_;
json_pointer pointer_;
protected:
// decodes a JSON uri and replaces all or part of the currently stored values
void from_string(const std::string &uri);
std::tuple<std::string, std::string, std::string, std::string, std::string> tie() const
{
return std::tie(urn_, proto_, hostname_, path_, pointer_.to_string());
}
public:
json_uri(const std::string &uri)
{
from_string(uri);
}
const std::string protocol() const { return proto_; }
const std::string hostname() const { return hostname_; }
const std::string path() const { return path_; }
const json_pointer pointer() const { return pointer_; }
const std::string url() const;
// decode and encode strings for ~ and % escape sequences
static std::string unescape(const std::string &);
static std::string escape(const std::string &);
// create a new json_uri based in this one and the given uri
// resolves relative changes (pathes or pointers) and resets part if proto or hostname changes
json_uri derive(const std::string &uri) const
{
json_uri u = *this;
u.from_string(uri);
return u;
}
// append a pointer-field to the pointer-part of this uri
json_uri append(const std::string &field) const
{
json_uri u = *this;
u.pointer_.append("/" + field);
return u;
}
std::string to_string() const;
friend bool operator<(const json_uri &l, const json_uri &r)
{
return l.tie() < r.tie();
}
friend bool operator==(const json_uri &l, const json_uri &r)
{
return l.tie() == r.tie();
}
friend std::ostream &operator<<(std::ostream &os, const json_uri &u);
};
namespace json_schema_draft4
{
extern json draft4_schema_builtin;
class JSON_SCHEMA_VALIDATOR_API json_validator
{
std::vector<std::shared_ptr<json>> schema_store_;
std::shared_ptr<json> root_schema_;
std::function<void(const json_uri &, json &)> schema_loader_ = nullptr;
std::function<void(const std::string &, const std::string &)> format_check_ = nullptr;
std::map<json_uri, const json *> schema_refs_;
void validate(const json &instance, const json &schema_, const std::string &name);
void validate_array(const json &instance, const json &schema_, const std::string &name);
void validate_object(const json &instance, const json &schema_, const std::string &name);
void validate_string(const json &instance, const json &schema, const std::string &name);
void insert_schema(const json &input, const json_uri &id);
public:
json_validator(std::function<void(const json_uri &, json &)> loader = nullptr,
std::function<void(const std::string &, const std::string &)> format = nullptr)
: schema_loader_(loader), format_check_(format)
{
}
// insert and set a root-schema
void set_root_schema(const json &);
// validate a json-document based on the root-schema
void validate(const json &instance);
};
} // json_schema_draft4
} // nlohmann
#endif /* NLOHMANN_JSON_SCHEMA_HPP__ */