Json
API reference
JSON document parsing examples
TEST(Example, ParsingSuccess_usingConstructor) {
// In this example you will se how to parse simple documet and traverse parsed nodes tree
const std::string document =
"{\n"
" \"someNumber\": 5,\n"
" \"someArray\": [\n"
" \"string\", true\n"
" ],\n"
" \"someObject\": {\"someNull\": null}\n"
"}";
rili::JSON json(document);
ASSERT_EQ(json.type(), rili::JSON::Type::Object); // our root element should be Object type({...})
auto const& root = json.object();
ASSERT_EQ(root.size(), 3u); // we have 3 elements inside root object - "someNumber", "someArray" and "someObject"
auto rootSubElementIt = root.begin();
ASSERT_NE(rootSubElementIt, root.end());
EXPECT_EQ(rootSubElementIt->first, "someNumber");
ASSERT_EQ(rootSubElementIt->second.type(), rili::JSON::Type::Number); // value type of someNumber is Number
EXPECT_EQ(rootSubElementIt->second.number(), "5"); // value of someNumber is 5
/**
NOTE: JSON numbers are not converted to C++ POD number types because such conversion is not valid for all possible
cases.
JSON format do not specify number type precision, maximal and minimal values etc. - because of that you can
theoretically have very big numbers in JSON document or numbers with precision bigger than double type can handle.
Some of users rather would like in these cases use dedicated big numbers library to handle these like GNU MP.
So we decided to not provide any conversions of numbers - instead we implement full number format validation defined
in JSON specification.
Aditional benefit is in better preformance of document parsing as converting numbers sometimes require
non-negliable cpu power.
*/
rootSubElementIt++; // we are going to next element in root object
ASSERT_NE(rootSubElementIt, root.end());
EXPECT_EQ(rootSubElementIt->first, "someArray");
ASSERT_EQ(rootSubElementIt->second.type(), rili::JSON::Type::Array); // value type of someArray is Array
auto const& array = rootSubElementIt->second.array();
ASSERT_EQ(array.size(), 2u); // someArray have 2 elements
ASSERT_EQ(array.front().type(), rili::JSON::Type::String); // first element type is String
ASSERT_EQ(array.back().type(), rili::JSON::Type::Boolean); // second element type is Boolean
EXPECT_EQ(array.front().string(), "string"); // first element value is "string"
EXPECT_TRUE(array.back().boolean()); // second element value is true
rootSubElementIt++; // we are going to next element in root object
ASSERT_NE(rootSubElementIt, root.end());
EXPECT_EQ(rootSubElementIt->first, "someObject");
ASSERT_EQ(rootSubElementIt->second.type(), rili::JSON::Type::Object); // value type of someObject is Object
ASSERT_EQ(rootSubElementIt->second.object().size(), 1u); // someObject have 1 element
EXPECT_EQ(rootSubElementIt->second.object().front().first, "someNull"); // someObject element name is "someNull"
EXPECT_EQ(rootSubElementIt->second.object().front().second.type(),
rili::JSON::Type::Null); // someNull value type is Null
rootSubElementIt++; // we are going to next element (end)
ASSERT_EQ(rootSubElementIt, root.end());
}
TEST(Example, ParsingSuccess_usingParseMethod) {
const std::string document =
"{\n"
" \"someNumber\": 5,\n"
" \"someArray\": [\n"
" \"string\", true\n"
" ],\n"
" \"someObject\": {\"someNull\": null}\n"
"}";
rili::JSON json; // now json object should have Null type
EXPECT_EQ(json.type(), rili::JSON::Type::Null);
json.parse(document);
EXPECT_EQ(json.type(),
rili::JSON::Type::Object); // it should be exactly the same like in ParsingSuccess_usingConstructor test
}
rili::JSON::SyntaxError
)
Parsing failure handling (TEST(Example, ParsingFailure) {
std::string document = "[1,2,3,4, \"5\", {]"; // here is invalid "{" without "}"
try {
rili::JSON json;
json.parse(document); // this shouldn't end succesfully
ADD_FAILURE();
} catch (rili::JSON::SyntaxError e) {
EXPECT_EQ(e.position(), 16u); // '{' is at 16 position in document
} catch (...) {
ADD_FAILURE();
}
EXPECT_THROW(rili::JSON::SyntaxError,
[&document]() { rili::JSON json(document); }); // the same like above but with constructor
}
Creating JSON document structure from scratch and serialization
TEST(Example, DataSerialization) {
// Here you will see how to create document nodes tree from scratch(similar to document from
// ParsingSuccess_usingConstructor) and then serialize it to JSON string.
rili::JSON json;
json.object({}); // we changed our root element type to Object and it should be value is empty (you can also use
// not empty if you want)
/* we will create something like that:
{
"someNumber": 5,
"someArray": [ "string", true ],
"someObject": {"someNull": null}
}
*/
auto& root = json.object();
root.push_back({"someNumber", rili::JSON()}); // here we create someNumber entry in root object with Null type
root.back().second.number("5"); // here we set someNumber type to Number + value to 5
root.push_back({"someArray", rili::JSON()}); // here we create someArray entry in root object with Null type
root.back().second.array(
{rili::JSON(), rili::JSON()}); // here we set someArray type to Array + value as array of two null type elemens
auto& someArray = root.back().second.array();
someArray.front().string("string"); // here we set first element value type to String + value equal to "string"
someArray.back().boolean(true); // here we set second element value type to Boolean + value equal to true
root.push_back({"someObject", rili::JSON()}); // here we create someObject entry in root object with Null type
root.back().second.object({{"someNull", rili::JSON()}}); // here we set someObject type to object and value as
// single null typed entry named "someNull"
auto const document = json.stringify(); // here we will serialize our document nodes tree to JSONformated string
EXPECT_EQ(document, "{\"someNumber\":5,\"someArray\":[\"string\",true],\"someObject\":{\"someNull\":null}}");
}
Changing document content
TEST(Example, DataModyfication) {
// Here you will see how to parse, change and serialize changed document
const std::string originalDocument =
"{\"someNumber\":5,\"someArray\":[\"string\",true],\"someObject\":{\"someNull\":null}}";
rili::JSON json(originalDocument);
json.object().back().first = "myObject"; // here we change entry name someObject -> myObject
json.object().back().second.object().back().first =
"emptyString"; // here we change entry name someNull -> emptyString
json.object().back().second.object().back().second.string(""); // here we change type from Null to String
json.object().back().second.object().push_back(
{"nonEmptyString", rili::JSON()}); // here we add entry nonEmptyString to myObject (with Null as value for now)
json.object().back().second.object().back().second.string(
"not empty"); // here we set nonEmptyString value as String with value "not empty"
auto it = json.object().begin();
it++;
json.object().erase(it); // here we erase someArrayEntry and all it subnodes
auto const changedDocument = json.stringify(); // here we serialize changed document
EXPECT_EQ(changedDocument,
"{\"someNumber\":5,\"myObject\":{\"emptyString\":\"\",\"nonEmptyString\":\"not empty\"}}");
}