Add some example code that was prepared for a Melbourne C++ lightning talk

This commit is contained in:
Tristan Penman 2017-07-10 12:57:14 +10:00
parent 64abe842b8
commit cff81eb2ab
6 changed files with 508 additions and 0 deletions

View File

@ -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)

View 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;
}
}
}

View 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
View 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;
}

View 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;
}

View 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;
}