Skip to content

Commit

Permalink
Add some example code that was prepared for a Melbourne C++ lightning…
Browse files Browse the repository at this point in the history
… talk
  • Loading branch information
tristanpenman committed Jul 10, 2017
1 parent 64abe84 commit cff81eb
Show file tree
Hide file tree
Showing 6 changed files with 508 additions and 0 deletions.
25 changes: 25 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 changes: 132 additions & 0 deletions examples/array_iteration_basics.cpp
Original file line number Diff line number Diff line change
@@ -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 changes: 65 additions & 0 deletions examples/array_iteration_template_fn.cpp
Original file line number Diff line number Diff line change
@@ -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 changes: 110 additions & 0 deletions examples/json_pointers.cpp
Original file line number Diff line number Diff line change
@@ -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;
}
Loading

0 comments on commit cff81eb

Please sign in to comment.