mirror of
https://github.com/tristanpenman/valijson.git
synced 2024-12-14 02:57:45 +01:00
Add some example code that was prepared for a Melbourne C++ lightning talk
This commit is contained in:
parent
64abe842b8
commit
cff81eb2ab
@ -80,6 +80,26 @@ add_executable(external_schema
|
||||
examples/external_schema.cpp
|
||||
)
|
||||
|
||||
add_executable(array_iteration_basics
|
||||
examples/array_iteration_basics.cpp
|
||||
)
|
||||
|
||||
add_executable(array_iteration_template_fn
|
||||
examples/array_iteration_template_fn.cpp
|
||||
)
|
||||
|
||||
add_executable(object_iteration
|
||||
examples/object_iteration.cpp
|
||||
)
|
||||
|
||||
add_executable(json_pointers
|
||||
examples/json_pointers.cpp
|
||||
)
|
||||
|
||||
add_executable(remote_resolution
|
||||
examples/remote_resolution.cpp
|
||||
)
|
||||
|
||||
set(TEST_SOURCES
|
||||
tests/test_adapter_comparison.cpp
|
||||
tests/test_fetch_document_callback.cpp
|
||||
@ -121,3 +141,8 @@ endif()
|
||||
target_link_libraries(test_suite ${TEST_LIBS} ${Boost_LIBRARIES})
|
||||
target_link_libraries(custom_schema ${Boost_LIBRARIES})
|
||||
target_link_libraries(external_schema ${Boost_LIBRARIES})
|
||||
target_link_libraries(array_iteration_basics jsoncpp)
|
||||
target_link_libraries(array_iteration_template_fn jsoncpp)
|
||||
target_link_libraries(object_iteration jsoncpp)
|
||||
target_link_libraries(json_pointers)
|
||||
target_link_libraries(remote_resolution curl curlpp)
|
||||
|
132
examples/array_iteration_basics.cpp
Normal file
132
examples/array_iteration_basics.cpp
Normal file
@ -0,0 +1,132 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @brief Demonstrates iteration over an array and type check functions
|
||||
*
|
||||
*/
|
||||
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
|
||||
// jsoncpp
|
||||
#include <json/json.h>
|
||||
#include <valijson/adapters/jsoncpp_adapter.hpp>
|
||||
#include <valijson/utils/jsoncpp_utils.hpp>
|
||||
|
||||
// RapidJSON
|
||||
#include <rapidjson/document.h>
|
||||
#include <valijson/adapters/rapidjson_adapter.hpp>
|
||||
#include <valijson/utils/rapidjson_utils.hpp>
|
||||
|
||||
using std::cerr;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using std::runtime_error;
|
||||
|
||||
// The first example uses RapidJson to load a JSON document. If the document
|
||||
// contains an array, this function will print any array values that have a
|
||||
// valid string representation.
|
||||
void usingRapidJson(const char *filename);
|
||||
|
||||
// The second example uses JsonCpp to perform the same task, but unlike the
|
||||
// RapidJson example, we see how to use strict type checks and exception
|
||||
// handling.
|
||||
void usingJsonCpp(const char *filename);
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc != 2) {
|
||||
cerr << "Usage: " << endl;
|
||||
cerr << " " << argv[0] << " <filename>" << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Load the document using rapidjson
|
||||
cout << "-- Iteration using RapidJSON --" << endl;
|
||||
usingRapidJson(argv[1]);
|
||||
cout << endl;
|
||||
|
||||
// Load the document using jsoncpp
|
||||
cout << "-- Iteration using jsoncpp --" << endl;
|
||||
usingJsonCpp(argv[1]);
|
||||
cout << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void usingRapidJson(const char *filename)
|
||||
{
|
||||
using valijson::adapters::RapidJsonAdapter;
|
||||
|
||||
rapidjson::Document document;
|
||||
if (!valijson::utils::loadDocument(filename, document)) {
|
||||
return;
|
||||
}
|
||||
|
||||
RapidJsonAdapter adapter(document);
|
||||
if (!adapter.isArray()) {
|
||||
cout << "Not an array." << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
cout << "Array values:" << endl;
|
||||
int index = 0;
|
||||
|
||||
// We support the old way of doing things...
|
||||
const RapidJsonAdapter::Array array = adapter.asArray();
|
||||
for (RapidJsonAdapter::Array::const_iterator itr = array.begin();
|
||||
itr != array.end(); ++itr) {
|
||||
cout << " " << index++ << ": ";
|
||||
|
||||
// Each element of the array is just another RapidJsonAdapter
|
||||
const RapidJsonAdapter &value = *itr;
|
||||
|
||||
// maybeString is a loose type check
|
||||
if (value.maybeString()) {
|
||||
// If a value may be a string, we are allowed to get a string
|
||||
// representation of the value using asString
|
||||
cout << value.asString();
|
||||
}
|
||||
|
||||
cout << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void usingJsonCpp(const char *filename)
|
||||
{
|
||||
Json::Value value;
|
||||
if (!valijson::utils::loadDocument(filename, value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
valijson::adapters::JsonCppAdapter adapter(value);
|
||||
|
||||
// isArray is a strict type check
|
||||
if (!adapter.isArray()) {
|
||||
cout << "Not an array." << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
cout << "Array values:" << endl;
|
||||
int index = 0;
|
||||
|
||||
// If a value is not an array, then calling getArray will cause a runtime
|
||||
// exception to be raised.
|
||||
for (auto value : adapter.getArray()) {
|
||||
cout << " " << index++ << ": ";
|
||||
|
||||
// isString is another strict type check. Valijson uses the convention
|
||||
// that strict type check functions are prefixed with 'is'.
|
||||
if (!value.isString()) {
|
||||
cout << "Not a string. ";
|
||||
}
|
||||
|
||||
try {
|
||||
// Also by convention, functions prefixed with 'get' will raise a
|
||||
// runtime exception if the value is not of the correct type.
|
||||
cout << value.getString() << endl;
|
||||
} catch (runtime_error &e) {
|
||||
cout << "Caught exception: " << e.what() << endl;
|
||||
}
|
||||
}
|
||||
}
|
65
examples/array_iteration_template_fn.cpp
Normal file
65
examples/array_iteration_template_fn.cpp
Normal file
@ -0,0 +1,65 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @brief Demonstrates iteration over an array using template functions
|
||||
*
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <json/json.h>
|
||||
#include <valijson/adapters/jsoncpp_adapter.hpp>
|
||||
#include <valijson/utils/jsoncpp_utils.hpp>
|
||||
|
||||
using std::cerr;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
template<class AdapterType>
|
||||
void iterateJsonArray(const AdapterType &adapter)
|
||||
{
|
||||
if (!adapter.isArray()) {
|
||||
cout << "Not an array." << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
cout << "Array values:" << endl;
|
||||
int index = 0;
|
||||
|
||||
for (auto value : adapter.getArray()) {
|
||||
cout << " " << index++ << ": ";
|
||||
|
||||
if (value.maybeString()) {
|
||||
cout << value.asString();
|
||||
}
|
||||
|
||||
cout << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void usingJsonCppWithTemplateFn(const char *filename)
|
||||
{
|
||||
Json::Value value;
|
||||
if (!valijson::utils::loadDocument(filename, value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
valijson::adapters::JsonCppAdapter adapter(value);
|
||||
iterateJsonArray(adapter);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc != 2) {
|
||||
cerr << "Usage: " << endl;
|
||||
cerr << " " << argv[0] << " <filename>" << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Load the document using jsoncpp and iterate over array using function template
|
||||
cout << "-- Array iteration using jsoncpp via template function --" << endl;
|
||||
usingJsonCppWithTemplateFn(argv[1]);
|
||||
cout << endl;
|
||||
|
||||
return 0;
|
||||
}
|
110
examples/json_pointers.cpp
Normal file
110
examples/json_pointers.cpp
Normal file
@ -0,0 +1,110 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @brief Demonstrates how to resolve JSON pointers against the current document
|
||||
*
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <rapidjson/document.h>
|
||||
|
||||
#include <valijson/adapters/rapidjson_adapter.hpp>
|
||||
#include <valijson/internal/json_pointer.hpp>
|
||||
#include <valijson/internal/json_reference.hpp>
|
||||
#include <valijson/utils/rapidjson_utils.hpp>
|
||||
|
||||
using std::cerr;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
template<typename AdapterType>
|
||||
std::string maybeResolveRef(const AdapterType &value, const AdapterType &root)
|
||||
{
|
||||
if (!value.isObject()) {
|
||||
// Not an object, therefore not a JSON reference
|
||||
return "";
|
||||
}
|
||||
|
||||
const auto &object = value.getObject();
|
||||
const auto itr = object.find("$ref");
|
||||
if (itr == object.end()) {
|
||||
// Object does not contain $ref property
|
||||
return "";
|
||||
}
|
||||
|
||||
const AdapterType maybeRef = itr->second;
|
||||
if (!maybeRef.isString()) {
|
||||
return "[$ref did not contain a string value]";
|
||||
}
|
||||
|
||||
// Attempt to extract a JSON pointer
|
||||
const std::string ref = maybeRef.getString();
|
||||
const auto maybePointer = valijson::internal::json_reference::getJsonReferencePointer(ref);
|
||||
if (!maybePointer) {
|
||||
return "[$ref did not contain valid JSON pointer]";
|
||||
}
|
||||
|
||||
const auto refAdapter = valijson::internal::json_pointer::resolveJsonPointer(root, *maybePointer);
|
||||
if (!refAdapter.maybeString()) {
|
||||
return "[$ref did not point to a string value]";
|
||||
}
|
||||
|
||||
return refAdapter.asString();
|
||||
}
|
||||
|
||||
template<typename AdapterType>
|
||||
void iterateJsonObject(const AdapterType &adapter)
|
||||
{
|
||||
if (!adapter.maybeObject()) {
|
||||
cout << "Not an object." << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
cout << "Object members:" << endl;
|
||||
|
||||
// JSON objects are an unordered collection of key-value pairs,
|
||||
// so the members of the object may be printed in an order that is
|
||||
// different to that in the source JSON document.
|
||||
for (auto member : adapter.asObject()) {
|
||||
// The key is a std::string that can be accessed using 'first'
|
||||
cout << " " << member.first << ": ";
|
||||
|
||||
// The value is just another Adapter, and can be accessed using 'second'
|
||||
const AdapterType &value = member.second;
|
||||
if (value.maybeString()) {
|
||||
cout << value.asString();
|
||||
} else {
|
||||
cout << maybeResolveRef(value, adapter);
|
||||
}
|
||||
|
||||
cout << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void usingJsonCppWithTemplateFn(const char *filename)
|
||||
{
|
||||
rapidjson::Document document;
|
||||
if (!valijson::utils::loadDocument(filename, document)) {
|
||||
return;
|
||||
}
|
||||
|
||||
valijson::adapters::RapidJsonAdapter adapter(document);
|
||||
iterateJsonObject(adapter);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc != 2) {
|
||||
cerr << "Usage: " << endl;
|
||||
cerr << " " << argv[0] << " <filename>" << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Load the document using jsoncpp and iterate over array using function template
|
||||
cout << "-- Resolving JSON pointers using RapidJSON --" << endl;
|
||||
usingJsonCppWithTemplateFn(argv[1]);
|
||||
cout << endl;
|
||||
|
||||
return 0;
|
||||
}
|
69
examples/object_iteration.cpp
Normal file
69
examples/object_iteration.cpp
Normal file
@ -0,0 +1,69 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @brief Demonstrates iteration over the members of an object
|
||||
*
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <json/json.h>
|
||||
#include <valijson/adapters/jsoncpp_adapter.hpp>
|
||||
#include <valijson/utils/jsoncpp_utils.hpp>
|
||||
|
||||
using std::cerr;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
template<typename AdapterType>
|
||||
void iterateJsonObject(const AdapterType &adapter)
|
||||
{
|
||||
if (!adapter.maybeObject()) {
|
||||
cout << "Not an object." << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
cout << "Object members:" << endl;
|
||||
|
||||
// JSON objects are an unordered collection of key-value pairs,
|
||||
// so the members of the object may be printed in an order that is
|
||||
// different to that in the source JSON document.
|
||||
for (auto member : adapter.asObject()) {
|
||||
// The key is a std::string that can be accessed using 'first'
|
||||
cout << " " << member.first << ": ";
|
||||
|
||||
// The value is just another Adapter, and can be accessed using 'second'
|
||||
const AdapterType &value = member.second;
|
||||
if (value.maybeString()) {
|
||||
cout << value.asString();
|
||||
}
|
||||
|
||||
cout << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void usingJsonCppWithTemplateFn(const char *filename)
|
||||
{
|
||||
Json::Value value;
|
||||
if (!valijson::utils::loadDocument(filename, value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
valijson::adapters::JsonCppAdapter adapter(value);
|
||||
iterateJsonObject(adapter);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc != 2) {
|
||||
cerr << "Usage: " << endl;
|
||||
cerr << " " << argv[0] << " <filename>" << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
cout << "-- Object iteration using jsoncpp via template function --" << endl;
|
||||
usingJsonCppWithTemplateFn(argv[1]);
|
||||
cout << endl;
|
||||
|
||||
return 0;
|
||||
}
|
107
examples/remote_resolution.cpp
Normal file
107
examples/remote_resolution.cpp
Normal file
@ -0,0 +1,107 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @brief Demonstrates resolution of remote JSON references using cURLpp
|
||||
*
|
||||
*/
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <curlpp/cURLpp.hpp>
|
||||
#include <curlpp/Options.hpp>
|
||||
|
||||
#include <rapidjson/document.h>
|
||||
|
||||
#include <valijson/adapters/rapidjson_adapter.hpp>
|
||||
#include <valijson/utils/rapidjson_utils.hpp>
|
||||
#include <valijson/schema.hpp>
|
||||
#include <valijson/schema_parser.hpp>
|
||||
#include <valijson/validation_results.hpp>
|
||||
#include <valijson/validator.hpp>
|
||||
|
||||
using std::cerr;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
using valijson::Schema;
|
||||
using valijson::SchemaParser;
|
||||
using valijson::Validator;
|
||||
using valijson::ValidationResults;
|
||||
using valijson::adapters::RapidJsonAdapter;
|
||||
|
||||
const rapidjson::Document * fetchDocument(const std::string &uri)
|
||||
{
|
||||
cout << "Fetching " << uri << "..." << endl;
|
||||
curlpp::Cleanup myCleanup;
|
||||
std::ostringstream os;
|
||||
os << curlpp::options::Url(uri);
|
||||
rapidjson::Document *fetchedRoot = new rapidjson::Document();
|
||||
fetchedRoot->template Parse<0>(os.str().c_str());
|
||||
return fetchedRoot;
|
||||
}
|
||||
|
||||
void freeDocument(const rapidjson::Document *adapter)
|
||||
{
|
||||
delete adapter;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc != 3) {
|
||||
cerr << "Usage: " << argv[0] << " <schema document> <test/target document>" << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Load the document containing the schema
|
||||
rapidjson::Document schemaDocument;
|
||||
if (!valijson::utils::loadDocument(argv[1], schemaDocument)) {
|
||||
cerr << "Failed to load schema document." << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Load the document that is to be validated
|
||||
rapidjson::Document targetDocument;
|
||||
if (!valijson::utils::loadDocument(argv[2], targetDocument)) {
|
||||
cerr << "Failed to load target document." << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Parse the json schema into an internal schema format
|
||||
Schema schema;
|
||||
SchemaParser parser;
|
||||
RapidJsonAdapter schemaDocumentAdapter(schemaDocument);
|
||||
try {
|
||||
parser.populateSchema(schemaDocumentAdapter, schema, fetchDocument, freeDocument);
|
||||
} catch (std::exception &e) {
|
||||
cerr << "Failed to parse schema: " << e.what() << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Perform validation
|
||||
Validator validator(Validator::kWeakTypes);
|
||||
ValidationResults results;
|
||||
RapidJsonAdapter targetDocumentAdapter(targetDocument);
|
||||
if (!validator.validate(schema, targetDocumentAdapter, &results)) {
|
||||
std::cerr << "Validation failed." << endl;
|
||||
ValidationResults::Error error;
|
||||
unsigned int errorNum = 1;
|
||||
while (results.popError(error)) {
|
||||
|
||||
std::string context;
|
||||
std::vector<std::string>::iterator itr = error.context.begin();
|
||||
for (; itr != error.context.end(); itr++) {
|
||||
context += *itr;
|
||||
}
|
||||
|
||||
cerr << "Error #" << errorNum << std::endl
|
||||
<< " context: " << context << endl
|
||||
<< " desc: " << error.description << endl;
|
||||
++errorNum;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user