Convert DITLs to JSON

This commit is contained in:
elasota
2020-02-07 02:45:45 -05:00
parent 507019abda
commit 7c3dc7d1a3
238 changed files with 53935 additions and 39 deletions

View File

@@ -0,0 +1,46 @@
cmake_minimum_required(VERSION 2.8)
if(POLICY CMP0054)
cmake_policy(SET CMP0054 NEW)
endif()
set(EXAMPLES
capitalize
condense
filterkey
filterkeydom
jsonx
lookaheadparser
messagereader
parsebyparts
pretty
prettyauto
schemavalidator
serialize
simpledom
simplereader
simplepullreader
simplewriter
sortkeys
tutorial)
include_directories("../include/")
add_definitions(-D__STDC_FORMAT_MACROS)
set_property(DIRECTORY PROPERTY COMPILE_OPTIONS ${EXTRA_CXX_FLAGS})
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
endif()
add_executable(archivertest archiver/archiver.cpp archiver/archivertest.cpp)
foreach (example ${EXAMPLES})
add_executable(${example} ${example}/${example}.cpp)
endforeach()
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
target_link_libraries(parsebyparts pthread)
endif()
add_custom_target(examples ALL DEPENDS ${EXAMPLES})

View File

@@ -0,0 +1,292 @@
#include "archiver.h"
#include <cassert>
#include <stack>
#include "rapidjson/document.h"
#include "rapidjson/prettywriter.h"
#include "rapidjson/stringbuffer.h"
using namespace rapidjson;
struct JsonReaderStackItem {
enum State {
BeforeStart, //!< An object/array is in the stack but it is not yet called by StartObject()/StartArray().
Started, //!< An object/array is called by StartObject()/StartArray().
Closed //!< An array is closed after read all element, but before EndArray().
};
JsonReaderStackItem(const Value* value, State state) : value(value), state(state), index() {}
const Value* value;
State state;
SizeType index; // For array iteration
};
typedef std::stack<JsonReaderStackItem> JsonReaderStack;
#define DOCUMENT reinterpret_cast<Document*>(mDocument)
#define STACK (reinterpret_cast<JsonReaderStack*>(mStack))
#define TOP (STACK->top())
#define CURRENT (*TOP.value)
JsonReader::JsonReader(const char* json) : mDocument(), mStack(), mError(false) {
mDocument = new Document;
DOCUMENT->Parse(json);
if (DOCUMENT->HasParseError())
mError = true;
else {
mStack = new JsonReaderStack;
STACK->push(JsonReaderStackItem(DOCUMENT, JsonReaderStackItem::BeforeStart));
}
}
JsonReader::~JsonReader() {
delete DOCUMENT;
delete STACK;
}
// Archive concept
JsonReader& JsonReader::StartObject() {
if (!mError) {
if (CURRENT.IsObject() && TOP.state == JsonReaderStackItem::BeforeStart)
TOP.state = JsonReaderStackItem::Started;
else
mError = true;
}
return *this;
}
JsonReader& JsonReader::EndObject() {
if (!mError) {
if (CURRENT.IsObject() && TOP.state == JsonReaderStackItem::Started)
Next();
else
mError = true;
}
return *this;
}
JsonReader& JsonReader::Member(const char* name) {
if (!mError) {
if (CURRENT.IsObject() && TOP.state == JsonReaderStackItem::Started) {
Value::ConstMemberIterator memberItr = CURRENT.FindMember(name);
if (memberItr != CURRENT.MemberEnd())
STACK->push(JsonReaderStackItem(&memberItr->value, JsonReaderStackItem::BeforeStart));
else
mError = true;
}
else
mError = true;
}
return *this;
}
bool JsonReader::HasMember(const char* name) const {
if (!mError && CURRENT.IsObject() && TOP.state == JsonReaderStackItem::Started)
return CURRENT.HasMember(name);
return false;
}
JsonReader& JsonReader::StartArray(size_t* size) {
if (!mError) {
if (CURRENT.IsArray() && TOP.state == JsonReaderStackItem::BeforeStart) {
TOP.state = JsonReaderStackItem::Started;
if (size)
*size = CURRENT.Size();
if (!CURRENT.Empty()) {
const Value* value = &CURRENT[TOP.index];
STACK->push(JsonReaderStackItem(value, JsonReaderStackItem::BeforeStart));
}
else
TOP.state = JsonReaderStackItem::Closed;
}
else
mError = true;
}
return *this;
}
JsonReader& JsonReader::EndArray() {
if (!mError) {
if (CURRENT.IsArray() && TOP.state == JsonReaderStackItem::Closed)
Next();
else
mError = true;
}
return *this;
}
JsonReader& JsonReader::operator&(bool& b) {
if (!mError) {
if (CURRENT.IsBool()) {
b = CURRENT.GetBool();
Next();
}
else
mError = true;
}
return *this;
}
JsonReader& JsonReader::operator&(unsigned& u) {
if (!mError) {
if (CURRENT.IsUint()) {
u = CURRENT.GetUint();
Next();
}
else
mError = true;
}
return *this;
}
JsonReader& JsonReader::operator&(int& i) {
if (!mError) {
if (CURRENT.IsInt()) {
i = CURRENT.GetInt();
Next();
}
else
mError = true;
}
return *this;
}
JsonReader& JsonReader::operator&(double& d) {
if (!mError) {
if (CURRENT.IsNumber()) {
d = CURRENT.GetDouble();
Next();
}
else
mError = true;
}
return *this;
}
JsonReader& JsonReader::operator&(std::string& s) {
if (!mError) {
if (CURRENT.IsString()) {
s = CURRENT.GetString();
Next();
}
else
mError = true;
}
return *this;
}
JsonReader& JsonReader::SetNull() {
// This function is for JsonWriter only.
mError = true;
return *this;
}
void JsonReader::Next() {
if (!mError) {
assert(!STACK->empty());
STACK->pop();
if (!STACK->empty() && CURRENT.IsArray()) {
if (TOP.state == JsonReaderStackItem::Started) { // Otherwise means reading array item pass end
if (TOP.index < CURRENT.Size() - 1) {
const Value* value = &CURRENT[++TOP.index];
STACK->push(JsonReaderStackItem(value, JsonReaderStackItem::BeforeStart));
}
else
TOP.state = JsonReaderStackItem::Closed;
}
else
mError = true;
}
}
}
#undef DOCUMENT
#undef STACK
#undef TOP
#undef CURRENT
////////////////////////////////////////////////////////////////////////////////
// JsonWriter
#define WRITER reinterpret_cast<PrettyWriter<StringBuffer>*>(mWriter)
#define STREAM reinterpret_cast<StringBuffer*>(mStream)
JsonWriter::JsonWriter() : mWriter(), mStream() {
mStream = new StringBuffer;
mWriter = new PrettyWriter<StringBuffer>(*STREAM);
}
JsonWriter::~JsonWriter() {
delete WRITER;
delete STREAM;
}
const char* JsonWriter::GetString() const {
return STREAM->GetString();
}
JsonWriter& JsonWriter::StartObject() {
WRITER->StartObject();
return *this;
}
JsonWriter& JsonWriter::EndObject() {
WRITER->EndObject();
return *this;
}
JsonWriter& JsonWriter::Member(const char* name) {
WRITER->String(name, static_cast<SizeType>(strlen(name)));
return *this;
}
bool JsonWriter::HasMember(const char*) const {
// This function is for JsonReader only.
assert(false);
return false;
}
JsonWriter& JsonWriter::StartArray(size_t*) {
WRITER->StartArray();
return *this;
}
JsonWriter& JsonWriter::EndArray() {
WRITER->EndArray();
return *this;
}
JsonWriter& JsonWriter::operator&(bool& b) {
WRITER->Bool(b);
return *this;
}
JsonWriter& JsonWriter::operator&(unsigned& u) {
WRITER->Uint(u);
return *this;
}
JsonWriter& JsonWriter::operator&(int& i) {
WRITER->Int(i);
return *this;
}
JsonWriter& JsonWriter::operator&(double& d) {
WRITER->Double(d);
return *this;
}
JsonWriter& JsonWriter::operator&(std::string& s) {
WRITER->String(s.c_str(), static_cast<SizeType>(s.size()));
return *this;
}
JsonWriter& JsonWriter::SetNull() {
WRITER->Null();
return *this;
}
#undef STREAM
#undef WRITER

View File

@@ -0,0 +1,145 @@
#ifndef ARCHIVER_H_
#define ARCHIVER_H_
#include <cstddef>
#include <string>
/**
\class Archiver
\brief Archiver concept
Archiver can be a reader or writer for serialization or deserialization respectively.
class Archiver {
public:
/// \returns true if the archiver is in normal state. false if it has errors.
operator bool() const;
/// Starts an object
Archiver& StartObject();
/// After calling StartObject(), assign a member with a name
Archiver& Member(const char* name);
/// After calling StartObject(), check if a member presents
bool HasMember(const char* name) const;
/// Ends an object
Archiver& EndObject();
/// Starts an array
/// \param size If Archiver::IsReader is true, the size of array is written.
Archiver& StartArray(size_t* size = 0);
/// Ends an array
Archiver& EndArray();
/// Read/Write primitive types.
Archiver& operator&(bool& b);
Archiver& operator&(unsigned& u);
Archiver& operator&(int& i);
Archiver& operator&(double& d);
Archiver& operator&(std::string& s);
/// Write primitive types.
Archiver& SetNull();
//! Whether it is a reader.
static const bool IsReader;
//! Whether it is a writer.
static const bool IsWriter;
};
*/
/// Represents a JSON reader which implements Archiver concept.
class JsonReader {
public:
/// Constructor.
/**
\param json A non-const source json string for in-situ parsing.
\note in-situ means the source JSON string will be modified after parsing.
*/
JsonReader(const char* json);
/// Destructor.
~JsonReader();
// Archive concept
operator bool() const { return !mError; }
JsonReader& StartObject();
JsonReader& Member(const char* name);
bool HasMember(const char* name) const;
JsonReader& EndObject();
JsonReader& StartArray(size_t* size = 0);
JsonReader& EndArray();
JsonReader& operator&(bool& b);
JsonReader& operator&(unsigned& u);
JsonReader& operator&(int& i);
JsonReader& operator&(double& d);
JsonReader& operator&(std::string& s);
JsonReader& SetNull();
static const bool IsReader = true;
static const bool IsWriter = !IsReader;
private:
JsonReader(const JsonReader&);
JsonReader& operator=(const JsonReader&);
void Next();
// PIMPL
void* mDocument; ///< DOM result of parsing.
void* mStack; ///< Stack for iterating the DOM
bool mError; ///< Whether an error has occurred.
};
class JsonWriter {
public:
/// Constructor.
JsonWriter();
/// Destructor.
~JsonWriter();
/// Obtains the serialized JSON string.
const char* GetString() const;
// Archive concept
operator bool() const { return true; }
JsonWriter& StartObject();
JsonWriter& Member(const char* name);
bool HasMember(const char* name) const;
JsonWriter& EndObject();
JsonWriter& StartArray(size_t* size = 0);
JsonWriter& EndArray();
JsonWriter& operator&(bool& b);
JsonWriter& operator&(unsigned& u);
JsonWriter& operator&(int& i);
JsonWriter& operator&(double& d);
JsonWriter& operator&(std::string& s);
JsonWriter& SetNull();
static const bool IsReader = false;
static const bool IsWriter = !IsReader;
private:
JsonWriter(const JsonWriter&);
JsonWriter& operator=(const JsonWriter&);
// PIMPL idiom
void* mWriter; ///< JSON writer.
void* mStream; ///< Stream buffer.
};
#endif // ARCHIVER_H__

View File

@@ -0,0 +1,287 @@
#include "archiver.h"
#include <iostream>
#include <vector>
//////////////////////////////////////////////////////////////////////////////
// Test1: simple object
struct Student {
Student() : name(), age(), height(), canSwim() {}
Student(const std::string name, unsigned age, double height, bool canSwim) :
name(name), age(age), height(height), canSwim(canSwim)
{}
std::string name;
unsigned age;
double height;
bool canSwim;
};
template <typename Archiver>
Archiver& operator&(Archiver& ar, Student& s) {
ar.StartObject();
ar.Member("name") & s.name;
ar.Member("age") & s.age;
ar.Member("height") & s.height;
ar.Member("canSwim") & s.canSwim;
return ar.EndObject();
}
std::ostream& operator<<(std::ostream& os, const Student& s) {
return os << s.name << " " << s.age << " " << s.height << " " << s.canSwim;
}
void test1() {
std::string json;
// Serialize
{
Student s("Lua", 9, 150.5, true);
JsonWriter writer;
writer & s;
json = writer.GetString();
std::cout << json << std::endl;
}
// Deserialize
{
Student s;
JsonReader reader(json.c_str());
reader & s;
std::cout << s << std::endl;
}
}
//////////////////////////////////////////////////////////////////////////////
// Test2: std::vector <=> JSON array
//
// You can map a JSON array to other data structures as well
struct Group {
Group() : groupName(), students() {}
std::string groupName;
std::vector<Student> students;
};
template <typename Archiver>
Archiver& operator&(Archiver& ar, Group& g) {
ar.StartObject();
ar.Member("groupName");
ar & g.groupName;
ar.Member("students");
size_t studentCount = g.students.size();
ar.StartArray(&studentCount);
if (ar.IsReader)
g.students.resize(studentCount);
for (size_t i = 0; i < studentCount; i++)
ar & g.students[i];
ar.EndArray();
return ar.EndObject();
}
std::ostream& operator<<(std::ostream& os, const Group& g) {
os << g.groupName << std::endl;
for (std::vector<Student>::const_iterator itr = g.students.begin(); itr != g.students.end(); ++itr)
os << *itr << std::endl;
return os;
}
void test2() {
std::string json;
// Serialize
{
Group g;
g.groupName = "Rainbow";
Student s1("Lua", 9, 150.5, true);
Student s2("Mio", 7, 120.0, false);
g.students.push_back(s1);
g.students.push_back(s2);
JsonWriter writer;
writer & g;
json = writer.GetString();
std::cout << json << std::endl;
}
// Deserialize
{
Group g;
JsonReader reader(json.c_str());
reader & g;
std::cout << g << std::endl;
}
}
//////////////////////////////////////////////////////////////////////////////
// Test3: polymorphism & friend
//
// Note that friendship is not necessary but make things simpler.
class Shape {
public:
virtual ~Shape() {}
virtual const char* GetType() const = 0;
virtual void Print(std::ostream& os) const = 0;
protected:
Shape() : x_(), y_() {}
Shape(double x, double y) : x_(x), y_(y) {}
template <typename Archiver>
friend Archiver& operator&(Archiver& ar, Shape& s);
double x_, y_;
};
template <typename Archiver>
Archiver& operator&(Archiver& ar, Shape& s) {
ar.Member("x") & s.x_;
ar.Member("y") & s.y_;
return ar;
}
class Circle : public Shape {
public:
Circle() : radius_() {}
Circle(double x, double y, double radius) : Shape(x, y), radius_(radius) {}
~Circle() {}
const char* GetType() const { return "Circle"; }
void Print(std::ostream& os) const {
os << "Circle (" << x_ << ", " << y_ << ")" << " radius = " << radius_;
}
private:
template <typename Archiver>
friend Archiver& operator&(Archiver& ar, Circle& c);
double radius_;
};
template <typename Archiver>
Archiver& operator&(Archiver& ar, Circle& c) {
ar & static_cast<Shape&>(c);
ar.Member("radius") & c.radius_;
return ar;
}
class Box : public Shape {
public:
Box() : width_(), height_() {}
Box(double x, double y, double width, double height) : Shape(x, y), width_(width), height_(height) {}
~Box() {}
const char* GetType() const { return "Box"; }
void Print(std::ostream& os) const {
os << "Box (" << x_ << ", " << y_ << ")" << " width = " << width_ << " height = " << height_;
}
private:
template <typename Archiver>
friend Archiver& operator&(Archiver& ar, Box& b);
double width_, height_;
};
template <typename Archiver>
Archiver& operator&(Archiver& ar, Box& b) {
ar & static_cast<Shape&>(b);
ar.Member("width") & b.width_;
ar.Member("height") & b.height_;
return ar;
}
class Canvas {
public:
Canvas() : shapes_() {}
~Canvas() { Clear(); }
void Clear() {
for (std::vector<Shape*>::iterator itr = shapes_.begin(); itr != shapes_.end(); ++itr)
delete *itr;
}
void AddShape(Shape* shape) { shapes_.push_back(shape); }
void Print(std::ostream& os) {
for (std::vector<Shape*>::iterator itr = shapes_.begin(); itr != shapes_.end(); ++itr) {
(*itr)->Print(os);
std::cout << std::endl;
}
}
private:
template <typename Archiver>
friend Archiver& operator&(Archiver& ar, Canvas& c);
std::vector<Shape*> shapes_;
};
template <typename Archiver>
Archiver& operator&(Archiver& ar, Shape*& shape) {
std::string type = ar.IsReader ? "" : shape->GetType();
ar.StartObject();
ar.Member("type") & type;
if (type == "Circle") {
if (ar.IsReader) shape = new Circle;
ar & static_cast<Circle&>(*shape);
}
else if (type == "Box") {
if (ar.IsReader) shape = new Box;
ar & static_cast<Box&>(*shape);
}
return ar.EndObject();
}
template <typename Archiver>
Archiver& operator&(Archiver& ar, Canvas& c) {
size_t shapeCount = c.shapes_.size();
ar.StartArray(&shapeCount);
if (ar.IsReader) {
c.Clear();
c.shapes_.resize(shapeCount);
}
for (size_t i = 0; i < shapeCount; i++)
ar & c.shapes_[i];
return ar.EndArray();
}
void test3() {
std::string json;
// Serialize
{
Canvas c;
c.AddShape(new Circle(1.0, 2.0, 3.0));
c.AddShape(new Box(4.0, 5.0, 6.0, 7.0));
JsonWriter writer;
writer & c;
json = writer.GetString();
std::cout << json << std::endl;
}
// Deserialize
{
Canvas c;
JsonReader reader(json.c_str());
reader & c;
c.Print(std::cout);
}
}
//////////////////////////////////////////////////////////////////////////////
int main() {
test1();
test2();
test3();
}

View File

@@ -0,0 +1,67 @@
// JSON condenser example
// This example parses JSON from stdin with validation,
// and re-output the JSON content to stdout with all string capitalized, and without whitespace.
#include "rapidjson/reader.h"
#include "rapidjson/writer.h"
#include "rapidjson/filereadstream.h"
#include "rapidjson/filewritestream.h"
#include "rapidjson/error/en.h"
#include <vector>
#include <cctype>
using namespace rapidjson;
template<typename OutputHandler>
struct CapitalizeFilter {
CapitalizeFilter(OutputHandler& out) : out_(out), buffer_() {}
bool Null() { return out_.Null(); }
bool Bool(bool b) { return out_.Bool(b); }
bool Int(int i) { return out_.Int(i); }
bool Uint(unsigned u) { return out_.Uint(u); }
bool Int64(int64_t i) { return out_.Int64(i); }
bool Uint64(uint64_t u) { return out_.Uint64(u); }
bool Double(double d) { return out_.Double(d); }
bool RawNumber(const char* str, SizeType length, bool copy) { return out_.RawNumber(str, length, copy); }
bool String(const char* str, SizeType length, bool) {
buffer_.clear();
for (SizeType i = 0; i < length; i++)
buffer_.push_back(static_cast<char>(std::toupper(str[i])));
return out_.String(&buffer_.front(), length, true); // true = output handler need to copy the string
}
bool StartObject() { return out_.StartObject(); }
bool Key(const char* str, SizeType length, bool copy) { return String(str, length, copy); }
bool EndObject(SizeType memberCount) { return out_.EndObject(memberCount); }
bool StartArray() { return out_.StartArray(); }
bool EndArray(SizeType elementCount) { return out_.EndArray(elementCount); }
OutputHandler& out_;
std::vector<char> buffer_;
private:
CapitalizeFilter(const CapitalizeFilter&);
CapitalizeFilter& operator=(const CapitalizeFilter&);
};
int main(int, char*[]) {
// Prepare JSON reader and input stream.
Reader reader;
char readBuffer[65536];
FileReadStream is(stdin, readBuffer, sizeof(readBuffer));
// Prepare JSON writer and output stream.
char writeBuffer[65536];
FileWriteStream os(stdout, writeBuffer, sizeof(writeBuffer));
Writer<FileWriteStream> writer(os);
// JSON reader parse from the input stream and let writer generate the output.
CapitalizeFilter<Writer<FileWriteStream> > filter(writer);
if (!reader.Parse(is, filter)) {
fprintf(stderr, "\nError(%u): %s\n", static_cast<unsigned>(reader.GetErrorOffset()), GetParseError_En(reader.GetParseErrorCode()));
return 1;
}
return 0;
}

View File

@@ -0,0 +1,32 @@
// JSON condenser example
// This example parses JSON text from stdin with validation,
// and re-output the JSON content to stdout without whitespace.
#include "rapidjson/reader.h"
#include "rapidjson/writer.h"
#include "rapidjson/filereadstream.h"
#include "rapidjson/filewritestream.h"
#include "rapidjson/error/en.h"
using namespace rapidjson;
int main(int, char*[]) {
// Prepare JSON reader and input stream.
Reader reader;
char readBuffer[65536];
FileReadStream is(stdin, readBuffer, sizeof(readBuffer));
// Prepare JSON writer and output stream.
char writeBuffer[65536];
FileWriteStream os(stdout, writeBuffer, sizeof(writeBuffer));
Writer<FileWriteStream> writer(os);
// JSON reader parse from the input stream and let writer generate the output.
if (!reader.Parse(is, writer)) {
fprintf(stderr, "\nError(%u): %s\n", static_cast<unsigned>(reader.GetErrorOffset()), GetParseError_En(reader.GetParseErrorCode()));
return 1;
}
return 0;
}

View File

@@ -0,0 +1,135 @@
// JSON filterkey example with SAX-style API.
// This example parses JSON text from stdin with validation.
// During parsing, specified key will be filtered using a SAX handler.
// It re-output the JSON content to stdout without whitespace.
#include "rapidjson/reader.h"
#include "rapidjson/writer.h"
#include "rapidjson/filereadstream.h"
#include "rapidjson/filewritestream.h"
#include "rapidjson/error/en.h"
#include <stack>
using namespace rapidjson;
// This handler forwards event into an output handler, with filtering the descendent events of specified key.
template <typename OutputHandler>
class FilterKeyHandler {
public:
typedef char Ch;
FilterKeyHandler(OutputHandler& outputHandler, const Ch* keyString, SizeType keyLength) :
outputHandler_(outputHandler), keyString_(keyString), keyLength_(keyLength), filterValueDepth_(), filteredKeyCount_()
{}
bool Null() { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.Null() && EndValue(); }
bool Bool(bool b) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.Bool(b) && EndValue(); }
bool Int(int i) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.Int(i) && EndValue(); }
bool Uint(unsigned u) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.Uint(u) && EndValue(); }
bool Int64(int64_t i) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.Int64(i) && EndValue(); }
bool Uint64(uint64_t u) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.Uint64(u) && EndValue(); }
bool Double(double d) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.Double(d) && EndValue(); }
bool RawNumber(const Ch* str, SizeType len, bool copy) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.RawNumber(str, len, copy) && EndValue(); }
bool String (const Ch* str, SizeType len, bool copy) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.String (str, len, copy) && EndValue(); }
bool StartObject() {
if (filterValueDepth_ > 0) {
filterValueDepth_++;
return true;
}
else {
filteredKeyCount_.push(0);
return outputHandler_.StartObject();
}
}
bool Key(const Ch* str, SizeType len, bool copy) {
if (filterValueDepth_ > 0)
return true;
else if (len == keyLength_ && std::memcmp(str, keyString_, len) == 0) {
filterValueDepth_ = 1;
return true;
}
else {
++filteredKeyCount_.top();
return outputHandler_.Key(str, len, copy);
}
}
bool EndObject(SizeType) {
if (filterValueDepth_ > 0) {
filterValueDepth_--;
return EndValue();
}
else {
// Use our own filtered memberCount
SizeType memberCount = filteredKeyCount_.top();
filteredKeyCount_.pop();
return outputHandler_.EndObject(memberCount) && EndValue();
}
}
bool StartArray() {
if (filterValueDepth_ > 0) {
filterValueDepth_++;
return true;
}
else
return outputHandler_.StartArray();
}
bool EndArray(SizeType elementCount) {
if (filterValueDepth_ > 0) {
filterValueDepth_--;
return EndValue();
}
else
return outputHandler_.EndArray(elementCount) && EndValue();
}
private:
FilterKeyHandler(const FilterKeyHandler&);
FilterKeyHandler& operator=(const FilterKeyHandler&);
bool EndValue() {
if (filterValueDepth_ == 1) // Just at the end of value after filtered key
filterValueDepth_ = 0;
return true;
}
OutputHandler& outputHandler_;
const char* keyString_;
const SizeType keyLength_;
unsigned filterValueDepth_;
std::stack<SizeType> filteredKeyCount_;
};
int main(int argc, char* argv[]) {
if (argc != 2) {
fprintf(stderr, "filterkey key < input.json > output.json\n");
return 1;
}
// Prepare JSON reader and input stream.
Reader reader;
char readBuffer[65536];
FileReadStream is(stdin, readBuffer, sizeof(readBuffer));
// Prepare JSON writer and output stream.
char writeBuffer[65536];
FileWriteStream os(stdout, writeBuffer, sizeof(writeBuffer));
Writer<FileWriteStream> writer(os);
// Prepare Filter
FilterKeyHandler<Writer<FileWriteStream> > filter(writer, argv[1], static_cast<SizeType>(strlen(argv[1])));
// JSON reader parse from the input stream, filter handler filters the events, and forward to writer.
// i.e. the events flow is: reader -> filter -> writer
if (!reader.Parse(is, filter)) {
fprintf(stderr, "\nError(%u): %s\n", static_cast<unsigned>(reader.GetErrorOffset()), GetParseError_En(reader.GetParseErrorCode()));
return 1;
}
return 0;
}

View File

@@ -0,0 +1,170 @@
// JSON filterkey example which populates filtered SAX events into a Document.
// This example parses JSON text from stdin with validation.
// During parsing, specified key will be filtered using a SAX handler.
// And finally the filtered events are used to populate a Document.
// As an example, the document is written to standard output.
#include "rapidjson/document.h"
#include "rapidjson/writer.h"
#include "rapidjson/filereadstream.h"
#include "rapidjson/filewritestream.h"
#include "rapidjson/error/en.h"
#include <stack>
using namespace rapidjson;
// This handler forwards event into an output handler, with filtering the descendent events of specified key.
template <typename OutputHandler>
class FilterKeyHandler {
public:
typedef char Ch;
FilterKeyHandler(OutputHandler& outputHandler, const Ch* keyString, SizeType keyLength) :
outputHandler_(outputHandler), keyString_(keyString), keyLength_(keyLength), filterValueDepth_(), filteredKeyCount_()
{}
bool Null() { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.Null() && EndValue(); }
bool Bool(bool b) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.Bool(b) && EndValue(); }
bool Int(int i) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.Int(i) && EndValue(); }
bool Uint(unsigned u) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.Uint(u) && EndValue(); }
bool Int64(int64_t i) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.Int64(i) && EndValue(); }
bool Uint64(uint64_t u) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.Uint64(u) && EndValue(); }
bool Double(double d) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.Double(d) && EndValue(); }
bool RawNumber(const Ch* str, SizeType len, bool copy) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.RawNumber(str, len, copy) && EndValue(); }
bool String (const Ch* str, SizeType len, bool copy) { return filterValueDepth_ > 0 ? EndValue() : outputHandler_.String (str, len, copy) && EndValue(); }
bool StartObject() {
if (filterValueDepth_ > 0) {
filterValueDepth_++;
return true;
}
else {
filteredKeyCount_.push(0);
return outputHandler_.StartObject();
}
}
bool Key(const Ch* str, SizeType len, bool copy) {
if (filterValueDepth_ > 0)
return true;
else if (len == keyLength_ && std::memcmp(str, keyString_, len) == 0) {
filterValueDepth_ = 1;
return true;
}
else {
++filteredKeyCount_.top();
return outputHandler_.Key(str, len, copy);
}
}
bool EndObject(SizeType) {
if (filterValueDepth_ > 0) {
filterValueDepth_--;
return EndValue();
}
else {
// Use our own filtered memberCount
SizeType memberCount = filteredKeyCount_.top();
filteredKeyCount_.pop();
return outputHandler_.EndObject(memberCount) && EndValue();
}
}
bool StartArray() {
if (filterValueDepth_ > 0) {
filterValueDepth_++;
return true;
}
else
return outputHandler_.StartArray();
}
bool EndArray(SizeType elementCount) {
if (filterValueDepth_ > 0) {
filterValueDepth_--;
return EndValue();
}
else
return outputHandler_.EndArray(elementCount) && EndValue();
}
private:
FilterKeyHandler(const FilterKeyHandler&);
FilterKeyHandler& operator=(const FilterKeyHandler&);
bool EndValue() {
if (filterValueDepth_ == 1) // Just at the end of value after filtered key
filterValueDepth_ = 0;
return true;
}
OutputHandler& outputHandler_;
const char* keyString_;
const SizeType keyLength_;
unsigned filterValueDepth_;
std::stack<SizeType> filteredKeyCount_;
};
// Implements a generator for Document::Populate()
template <typename InputStream>
class FilterKeyReader {
public:
typedef char Ch;
FilterKeyReader(InputStream& is, const Ch* keyString, SizeType keyLength) :
is_(is), keyString_(keyString), keyLength_(keyLength), parseResult_()
{}
// SAX event flow: reader -> filter -> handler
template <typename Handler>
bool operator()(Handler& handler) {
FilterKeyHandler<Handler> filter(handler, keyString_, keyLength_);
Reader reader;
parseResult_ = reader.Parse(is_, filter);
return parseResult_;
}
const ParseResult& GetParseResult() const { return parseResult_; }
private:
FilterKeyReader(const FilterKeyReader&);
FilterKeyReader& operator=(const FilterKeyReader&);
InputStream& is_;
const char* keyString_;
const SizeType keyLength_;
ParseResult parseResult_;
};
int main(int argc, char* argv[]) {
if (argc != 2) {
fprintf(stderr, "filterkeydom key < input.json > output.json\n");
return 1;
}
// Prepare input stream.
char readBuffer[65536];
FileReadStream is(stdin, readBuffer, sizeof(readBuffer));
// Prepare Filter
FilterKeyReader<FileReadStream> reader(is, argv[1], static_cast<SizeType>(strlen(argv[1])));
// Populates the filtered events from reader
Document document;
document.Populate(reader);
ParseResult pr = reader.GetParseResult();
if (!pr) {
fprintf(stderr, "\nError(%u): %s\n", static_cast<unsigned>(pr.Offset()), GetParseError_En(pr.Code()));
return 1;
}
// Prepare JSON writer and output stream.
char writeBuffer[65536];
FileWriteStream os(stdout, writeBuffer, sizeof(writeBuffer));
Writer<FileWriteStream> writer(os);
// Write the document to standard output
document.Accept(writer);
return 0;
}

View File

@@ -0,0 +1,207 @@
// JSON to JSONx conversion example, using SAX API.
// JSONx is an IBM standard format to represent JSON as XML.
// https://www-01.ibm.com/support/knowledgecenter/SS9H2Y_7.1.0/com.ibm.dp.doc/json_jsonx.html
// This example parses JSON text from stdin with validation,
// and convert to JSONx format to stdout.
// Need compile with -D__STDC_FORMAT_MACROS for defining PRId64 and PRIu64 macros.
#include "rapidjson/reader.h"
#include "rapidjson/stringbuffer.h"
#include "rapidjson/filereadstream.h"
#include "rapidjson/filewritestream.h"
#include "rapidjson/error/en.h"
#include <cstdio>
using namespace rapidjson;
// For simplicity, this example only read/write in UTF-8 encoding
template <typename OutputStream>
class JsonxWriter {
public:
JsonxWriter(OutputStream& os) : os_(os), name_(), level_(0), hasName_(false) {
}
bool Null() {
return WriteStartElement("null", true);
}
bool Bool(bool b) {
return
WriteStartElement("boolean") &&
WriteString(b ? "true" : "false") &&
WriteEndElement("boolean");
}
bool Int(int i) {
char buffer[12];
return WriteNumberElement(buffer, sprintf(buffer, "%d", i));
}
bool Uint(unsigned i) {
char buffer[11];
return WriteNumberElement(buffer, sprintf(buffer, "%u", i));
}
bool Int64(int64_t i) {
char buffer[21];
return WriteNumberElement(buffer, sprintf(buffer, "%" PRId64, i));
}
bool Uint64(uint64_t i) {
char buffer[21];
return WriteNumberElement(buffer, sprintf(buffer, "%" PRIu64, i));
}
bool Double(double d) {
char buffer[30];
return WriteNumberElement(buffer, sprintf(buffer, "%.17g", d));
}
bool RawNumber(const char* str, SizeType length, bool) {
return
WriteStartElement("number") &&
WriteEscapedText(str, length) &&
WriteEndElement("number");
}
bool String(const char* str, SizeType length, bool) {
return
WriteStartElement("string") &&
WriteEscapedText(str, length) &&
WriteEndElement("string");
}
bool StartObject() {
return WriteStartElement("object");
}
bool Key(const char* str, SizeType length, bool) {
// backup key to name_
name_.Clear();
for (SizeType i = 0; i < length; i++)
name_.Put(str[i]);
hasName_ = true;
return true;
}
bool EndObject(SizeType) {
return WriteEndElement("object");
}
bool StartArray() {
return WriteStartElement("array");
}
bool EndArray(SizeType) {
return WriteEndElement("array");
}
private:
bool WriteString(const char* s) {
while (*s)
os_.Put(*s++);
return true;
}
bool WriteEscapedAttributeValue(const char* s, size_t length) {
for (size_t i = 0; i < length; i++) {
switch (s[i]) {
case '&': WriteString("&amp;"); break;
case '<': WriteString("&lt;"); break;
case '"': WriteString("&quot;"); break;
default: os_.Put(s[i]); break;
}
}
return true;
}
bool WriteEscapedText(const char* s, size_t length) {
for (size_t i = 0; i < length; i++) {
switch (s[i]) {
case '&': WriteString("&amp;"); break;
case '<': WriteString("&lt;"); break;
default: os_.Put(s[i]); break;
}
}
return true;
}
bool WriteStartElement(const char* type, bool emptyElement = false) {
if (level_ == 0)
if (!WriteString("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"))
return false;
if (!WriteString("<json:") || !WriteString(type))
return false;
// For root element, need to add declarations
if (level_ == 0) {
if (!WriteString(
" xsi:schemaLocation=\"http://www.datapower.com/schemas/json jsonx.xsd\""
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
" xmlns:json=\"http://www.ibm.com/xmlns/prod/2009/jsonx\""))
return false;
}
if (hasName_) {
hasName_ = false;
if (!WriteString(" name=\"") ||
!WriteEscapedAttributeValue(name_.GetString(), name_.GetSize()) ||
!WriteString("\""))
return false;
}
if (emptyElement)
return WriteString("/>");
else {
level_++;
return WriteString(">");
}
}
bool WriteEndElement(const char* type) {
if (!WriteString("</json:") ||
!WriteString(type) ||
!WriteString(">"))
return false;
// For the last end tag, flush the output stream.
if (--level_ == 0)
os_.Flush();
return true;
}
bool WriteNumberElement(const char* buffer, int length) {
if (!WriteStartElement("number"))
return false;
for (int j = 0; j < length; j++)
os_.Put(buffer[j]);
return WriteEndElement("number");
}
OutputStream& os_;
StringBuffer name_;
unsigned level_;
bool hasName_;
};
int main(int, char*[]) {
// Prepare JSON reader and input stream.
Reader reader;
char readBuffer[65536];
FileReadStream is(stdin, readBuffer, sizeof(readBuffer));
// Prepare JSON writer and output stream.
char writeBuffer[65536];
FileWriteStream os(stdout, writeBuffer, sizeof(writeBuffer));
JsonxWriter<FileWriteStream> writer(os);
// JSON reader parse from the input stream and let writer generate the output.
if (!reader.Parse(is, writer)) {
fprintf(stderr, "\nError(%u): %s\n", static_cast<unsigned>(reader.GetErrorOffset()), GetParseError_En(reader.GetParseErrorCode()));
return 1;
}
return 0;
}

View File

@@ -0,0 +1,350 @@
#include "rapidjson/reader.h"
#include "rapidjson/document.h"
#include <iostream>
RAPIDJSON_DIAG_PUSH
#ifdef __GNUC__
RAPIDJSON_DIAG_OFF(effc++)
#endif
// This example demonstrates JSON token-by-token parsing with an API that is
// more direct; you don't need to design your logic around a handler object and
// callbacks. Instead, you retrieve values from the JSON stream by calling
// GetInt(), GetDouble(), GetString() and GetBool(), traverse into structures
// by calling EnterObject() and EnterArray(), and skip over unwanted data by
// calling SkipValue(). When you know your JSON's structure, this can be quite
// convenient.
//
// If you aren't sure of what's next in the JSON data, you can use PeekType() and
// PeekValue() to look ahead to the next object before reading it.
//
// If you call the wrong retrieval method--e.g. GetInt when the next JSON token is
// not an int, EnterObject or EnterArray when there isn't actually an object or array
// to read--the stream parsing will end immediately and no more data will be delivered.
//
// After calling EnterObject, you retrieve keys via NextObjectKey() and values via
// the normal getters. When NextObjectKey() returns null, you have exited the
// object, or you can call SkipObject() to skip to the end of the object
// immediately. If you fetch the entire object (i.e. NextObjectKey() returned null),
// you should not call SkipObject().
//
// After calling EnterArray(), you must alternate between calling NextArrayValue()
// to see if the array has more data, and then retrieving values via the normal
// getters. You can call SkipArray() to skip to the end of the array immediately.
// If you fetch the entire array (i.e. NextArrayValue() returned null),
// you should not call SkipArray().
//
// This parser uses in-situ strings, so the JSON buffer will be altered during the
// parse.
using namespace rapidjson;
class LookaheadParserHandler {
public:
bool Null() { st_ = kHasNull; v_.SetNull(); return true; }
bool Bool(bool b) { st_ = kHasBool; v_.SetBool(b); return true; }
bool Int(int i) { st_ = kHasNumber; v_.SetInt(i); return true; }
bool Uint(unsigned u) { st_ = kHasNumber; v_.SetUint(u); return true; }
bool Int64(int64_t i) { st_ = kHasNumber; v_.SetInt64(i); return true; }
bool Uint64(uint64_t u) { st_ = kHasNumber; v_.SetUint64(u); return true; }
bool Double(double d) { st_ = kHasNumber; v_.SetDouble(d); return true; }
bool RawNumber(const char*, SizeType, bool) { return false; }
bool String(const char* str, SizeType length, bool) { st_ = kHasString; v_.SetString(str, length); return true; }
bool StartObject() { st_ = kEnteringObject; return true; }
bool Key(const char* str, SizeType length, bool) { st_ = kHasKey; v_.SetString(str, length); return true; }
bool EndObject(SizeType) { st_ = kExitingObject; return true; }
bool StartArray() { st_ = kEnteringArray; return true; }
bool EndArray(SizeType) { st_ = kExitingArray; return true; }
protected:
LookaheadParserHandler(char* str);
void ParseNext();
protected:
enum LookaheadParsingState {
kInit,
kError,
kHasNull,
kHasBool,
kHasNumber,
kHasString,
kHasKey,
kEnteringObject,
kExitingObject,
kEnteringArray,
kExitingArray
};
Value v_;
LookaheadParsingState st_;
Reader r_;
InsituStringStream ss_;
static const int parseFlags = kParseDefaultFlags | kParseInsituFlag;
};
LookaheadParserHandler::LookaheadParserHandler(char* str) : v_(), st_(kInit), r_(), ss_(str) {
r_.IterativeParseInit();
ParseNext();
}
void LookaheadParserHandler::ParseNext() {
if (r_.HasParseError()) {
st_ = kError;
return;
}
r_.IterativeParseNext<parseFlags>(ss_, *this);
}
class LookaheadParser : protected LookaheadParserHandler {
public:
LookaheadParser(char* str) : LookaheadParserHandler(str) {}
bool EnterObject();
bool EnterArray();
const char* NextObjectKey();
bool NextArrayValue();
int GetInt();
double GetDouble();
const char* GetString();
bool GetBool();
void GetNull();
void SkipObject();
void SkipArray();
void SkipValue();
Value* PeekValue();
int PeekType(); // returns a rapidjson::Type, or -1 for no value (at end of object/array)
bool IsValid() { return st_ != kError; }
protected:
void SkipOut(int depth);
};
bool LookaheadParser::EnterObject() {
if (st_ != kEnteringObject) {
st_ = kError;
return false;
}
ParseNext();
return true;
}
bool LookaheadParser::EnterArray() {
if (st_ != kEnteringArray) {
st_ = kError;
return false;
}
ParseNext();
return true;
}
const char* LookaheadParser::NextObjectKey() {
if (st_ == kHasKey) {
const char* result = v_.GetString();
ParseNext();
return result;
}
if (st_ != kExitingObject) {
st_ = kError;
return 0;
}
ParseNext();
return 0;
}
bool LookaheadParser::NextArrayValue() {
if (st_ == kExitingArray) {
ParseNext();
return false;
}
if (st_ == kError || st_ == kExitingObject || st_ == kHasKey) {
st_ = kError;
return false;
}
return true;
}
int LookaheadParser::GetInt() {
if (st_ != kHasNumber || !v_.IsInt()) {
st_ = kError;
return 0;
}
int result = v_.GetInt();
ParseNext();
return result;
}
double LookaheadParser::GetDouble() {
if (st_ != kHasNumber) {
st_ = kError;
return 0.;
}
double result = v_.GetDouble();
ParseNext();
return result;
}
bool LookaheadParser::GetBool() {
if (st_ != kHasBool) {
st_ = kError;
return false;
}
bool result = v_.GetBool();
ParseNext();
return result;
}
void LookaheadParser::GetNull() {
if (st_ != kHasNull) {
st_ = kError;
return;
}
ParseNext();
}
const char* LookaheadParser::GetString() {
if (st_ != kHasString) {
st_ = kError;
return 0;
}
const char* result = v_.GetString();
ParseNext();
return result;
}
void LookaheadParser::SkipOut(int depth) {
do {
if (st_ == kEnteringArray || st_ == kEnteringObject) {
++depth;
}
else if (st_ == kExitingArray || st_ == kExitingObject) {
--depth;
}
else if (st_ == kError) {
return;
}
ParseNext();
}
while (depth > 0);
}
void LookaheadParser::SkipValue() {
SkipOut(0);
}
void LookaheadParser::SkipArray() {
SkipOut(1);
}
void LookaheadParser::SkipObject() {
SkipOut(1);
}
Value* LookaheadParser::PeekValue() {
if (st_ >= kHasNull && st_ <= kHasKey) {
return &v_;
}
return 0;
}
int LookaheadParser::PeekType() {
if (st_ >= kHasNull && st_ <= kHasKey) {
return v_.GetType();
}
if (st_ == kEnteringArray) {
return kArrayType;
}
if (st_ == kEnteringObject) {
return kObjectType;
}
return -1;
}
//-------------------------------------------------------------------------
int main() {
using namespace std;
char json[] = " { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null,"
"\"i\":123, \"pi\": 3.1416, \"a\":[-1, 2, 3, 4, \"array\", []], \"skipArrays\":[1, 2, [[[3]]]], "
"\"skipObject\":{ \"i\":0, \"t\":true, \"n\":null, \"d\":123.45 }, "
"\"skipNested\":[[[[{\"\":0}, {\"\":[-9.87]}]]], [], []], "
"\"skipString\":\"zzz\", \"reachedEnd\":null, \"t\":true }";
LookaheadParser r(json);
RAPIDJSON_ASSERT(r.PeekType() == kObjectType);
r.EnterObject();
while (const char* key = r.NextObjectKey()) {
if (0 == strcmp(key, "hello")) {
RAPIDJSON_ASSERT(r.PeekType() == kStringType);
cout << key << ":" << r.GetString() << endl;
}
else if (0 == strcmp(key, "t") || 0 == strcmp(key, "f")) {
RAPIDJSON_ASSERT(r.PeekType() == kTrueType || r.PeekType() == kFalseType);
cout << key << ":" << r.GetBool() << endl;
continue;
}
else if (0 == strcmp(key, "n")) {
RAPIDJSON_ASSERT(r.PeekType() == kNullType);
r.GetNull();
cout << key << endl;
continue;
}
else if (0 == strcmp(key, "pi")) {
RAPIDJSON_ASSERT(r.PeekType() == kNumberType);
cout << key << ":" << r.GetDouble() << endl;
continue;
}
else if (0 == strcmp(key, "a")) {
RAPIDJSON_ASSERT(r.PeekType() == kArrayType);
r.EnterArray();
cout << key << ":[ ";
while (r.NextArrayValue()) {
if (r.PeekType() == kNumberType) {
cout << r.GetDouble() << " ";
}
else if (r.PeekType() == kStringType) {
cout << r.GetString() << " ";
}
else {
r.SkipArray();
break;
}
}
cout << "]" << endl;
}
else {
cout << key << ":skipped" << endl;
r.SkipValue();
}
}
return 0;
}
RAPIDJSON_DIAG_POP

View File

@@ -0,0 +1,105 @@
// Reading a message JSON with Reader (SAX-style API).
// The JSON should be an object with key-string pairs.
#include "rapidjson/reader.h"
#include "rapidjson/error/en.h"
#include <iostream>
#include <string>
#include <map>
using namespace std;
using namespace rapidjson;
typedef map<string, string> MessageMap;
#if defined(__GNUC__)
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++)
#endif
#ifdef __clang__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(switch-enum)
#endif
struct MessageHandler
: public BaseReaderHandler<UTF8<>, MessageHandler> {
MessageHandler() : messages_(), state_(kExpectObjectStart), name_() {}
bool StartObject() {
switch (state_) {
case kExpectObjectStart:
state_ = kExpectNameOrObjectEnd;
return true;
default:
return false;
}
}
bool String(const char* str, SizeType length, bool) {
switch (state_) {
case kExpectNameOrObjectEnd:
name_ = string(str, length);
state_ = kExpectValue;
return true;
case kExpectValue:
messages_.insert(MessageMap::value_type(name_, string(str, length)));
state_ = kExpectNameOrObjectEnd;
return true;
default:
return false;
}
}
bool EndObject(SizeType) { return state_ == kExpectNameOrObjectEnd; }
bool Default() { return false; } // All other events are invalid.
MessageMap messages_;
enum State {
kExpectObjectStart,
kExpectNameOrObjectEnd,
kExpectValue
}state_;
std::string name_;
};
#if defined(__GNUC__)
RAPIDJSON_DIAG_POP
#endif
#ifdef __clang__
RAPIDJSON_DIAG_POP
#endif
static void ParseMessages(const char* json, MessageMap& messages) {
Reader reader;
MessageHandler handler;
StringStream ss(json);
if (reader.Parse(ss, handler))
messages.swap(handler.messages_); // Only change it if success.
else {
ParseErrorCode e = reader.GetParseErrorCode();
size_t o = reader.GetErrorOffset();
cout << "Error: " << GetParseError_En(e) << endl;;
cout << " at offset " << o << " near '" << string(json).substr(o, 10) << "...'" << endl;
}
}
int main() {
MessageMap messages;
const char* json1 = "{ \"greeting\" : \"Hello!\", \"farewell\" : \"bye-bye!\" }";
cout << json1 << endl;
ParseMessages(json1, messages);
for (MessageMap::const_iterator itr = messages.begin(); itr != messages.end(); ++itr)
cout << itr->first << ": " << itr->second << endl;
cout << endl << "Parse a JSON with invalid schema." << endl;
const char* json2 = "{ \"greeting\" : \"Hello!\", \"farewell\" : \"bye-bye!\", \"foo\" : {} }";
cout << json2 << endl;
ParseMessages(json2, messages);
return 0;
}

View File

@@ -0,0 +1,176 @@
// Example of parsing JSON to document by parts.
// Using C++11 threads
// Temporarily disable for clang (older version) due to incompatibility with libstdc++
#if (__cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1700)) && !defined(__clang__)
#include "rapidjson/document.h"
#include "rapidjson/error/en.h"
#include "rapidjson/writer.h"
#include "rapidjson/ostreamwrapper.h"
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
using namespace rapidjson;
template<unsigned parseFlags = kParseDefaultFlags>
class AsyncDocumentParser {
public:
AsyncDocumentParser(Document& d)
: stream_(*this)
, d_(d)
, parseThread_()
, mutex_()
, notEmpty_()
, finish_()
, completed_()
{
// Create and execute thread after all member variables are initialized.
parseThread_ = std::thread(&AsyncDocumentParser::Parse, this);
}
~AsyncDocumentParser() {
if (!parseThread_.joinable())
return;
{
std::unique_lock<std::mutex> lock(mutex_);
// Wait until the buffer is read up (or parsing is completed)
while (!stream_.Empty() && !completed_)
finish_.wait(lock);
// Automatically append '\0' as the terminator in the stream.
static const char terminator[] = "";
stream_.src_ = terminator;
stream_.end_ = terminator + 1;
notEmpty_.notify_one(); // unblock the AsyncStringStream
}
parseThread_.join();
}
void ParsePart(const char* buffer, size_t length) {
std::unique_lock<std::mutex> lock(mutex_);
// Wait until the buffer is read up (or parsing is completed)
while (!stream_.Empty() && !completed_)
finish_.wait(lock);
// Stop further parsing if the parsing process is completed.
if (completed_)
return;
// Set the buffer to stream and unblock the AsyncStringStream
stream_.src_ = buffer;
stream_.end_ = buffer + length;
notEmpty_.notify_one();
}
private:
void Parse() {
d_.ParseStream<parseFlags>(stream_);
// The stream may not be fully read, notify finish anyway to unblock ParsePart()
std::unique_lock<std::mutex> lock(mutex_);
completed_ = true; // Parsing process is completed
finish_.notify_one(); // Unblock ParsePart() or destructor if they are waiting.
}
struct AsyncStringStream {
typedef char Ch;
AsyncStringStream(AsyncDocumentParser& parser) : parser_(parser), src_(), end_(), count_() {}
char Peek() const {
std::unique_lock<std::mutex> lock(parser_.mutex_);
// If nothing in stream, block to wait.
while (Empty())
parser_.notEmpty_.wait(lock);
return *src_;
}
char Take() {
std::unique_lock<std::mutex> lock(parser_.mutex_);
// If nothing in stream, block to wait.
while (Empty())
parser_.notEmpty_.wait(lock);
count_++;
char c = *src_++;
// If all stream is read up, notify that the stream is finish.
if (Empty())
parser_.finish_.notify_one();
return c;
}
size_t Tell() const { return count_; }
// Not implemented
char* PutBegin() { return 0; }
void Put(char) {}
void Flush() {}
size_t PutEnd(char*) { return 0; }
bool Empty() const { return src_ == end_; }
AsyncDocumentParser& parser_;
const char* src_; //!< Current read position.
const char* end_; //!< End of buffer
size_t count_; //!< Number of characters taken so far.
};
AsyncStringStream stream_;
Document& d_;
std::thread parseThread_;
std::mutex mutex_;
std::condition_variable notEmpty_;
std::condition_variable finish_;
bool completed_;
};
int main() {
Document d;
{
AsyncDocumentParser<> parser(d);
const char json1[] = " { \"hello\" : \"world\", \"t\" : tr";
//const char json1[] = " { \"hello\" : \"world\", \"t\" : trX"; // For test parsing error
const char json2[] = "ue, \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.14";
const char json3[] = "16, \"a\":[1, 2, 3, 4] } ";
parser.ParsePart(json1, sizeof(json1) - 1);
parser.ParsePart(json2, sizeof(json2) - 1);
parser.ParsePart(json3, sizeof(json3) - 1);
}
if (d.HasParseError()) {
std::cout << "Error at offset " << d.GetErrorOffset() << ": " << GetParseError_En(d.GetParseError()) << std::endl;
return EXIT_FAILURE;
}
// Stringify the JSON to cout
OStreamWrapper os(std::cout);
Writer<OStreamWrapper> writer(os);
d.Accept(writer);
std::cout << std::endl;
return EXIT_SUCCESS;
}
#else // Not supporting C++11
#include <iostream>
int main() {
std::cout << "This example requires C++11 compiler" << std::endl;
}
#endif

View File

@@ -0,0 +1,30 @@
// JSON pretty formatting example
// This example can only handle UTF-8. For handling other encodings, see prettyauto example.
#include "rapidjson/reader.h"
#include "rapidjson/prettywriter.h"
#include "rapidjson/filereadstream.h"
#include "rapidjson/filewritestream.h"
#include "rapidjson/error/en.h"
using namespace rapidjson;
int main(int, char*[]) {
// Prepare reader and input stream.
Reader reader;
char readBuffer[65536];
FileReadStream is(stdin, readBuffer, sizeof(readBuffer));
// Prepare writer and output stream.
char writeBuffer[65536];
FileWriteStream os(stdout, writeBuffer, sizeof(writeBuffer));
PrettyWriter<FileWriteStream> writer(os);
// JSON reader parse from the input stream and let writer generate the output.
if (!reader.Parse<kParseValidateEncodingFlag>(is, writer)) {
fprintf(stderr, "\nError(%u): %s\n", static_cast<unsigned>(reader.GetErrorOffset()), GetParseError_En(reader.GetParseErrorCode()));
return 1;
}
return 0;
}

View File

@@ -0,0 +1,56 @@
// JSON pretty formatting example
// This example can handle UTF-8/UTF-16LE/UTF-16BE/UTF-32LE/UTF-32BE.
// The input firstly convert to UTF8, and then write to the original encoding with pretty formatting.
#include "rapidjson/reader.h"
#include "rapidjson/prettywriter.h"
#include "rapidjson/filereadstream.h"
#include "rapidjson/filewritestream.h"
#include "rapidjson/encodedstream.h" // NEW
#include "rapidjson/error/en.h"
#ifdef _WIN32
#include <fcntl.h>
#include <io.h>
#endif
using namespace rapidjson;
int main(int, char*[]) {
#ifdef _WIN32
// Prevent Windows converting between CR+LF and LF
_setmode(_fileno(stdin), _O_BINARY); // NEW
_setmode(_fileno(stdout), _O_BINARY); // NEW
#endif
// Prepare reader and input stream.
//Reader reader;
GenericReader<AutoUTF<unsigned>, UTF8<> > reader; // CHANGED
char readBuffer[65536];
FileReadStream is(stdin, readBuffer, sizeof(readBuffer));
AutoUTFInputStream<unsigned, FileReadStream> eis(is); // NEW
// Prepare writer and output stream.
char writeBuffer[65536];
FileWriteStream os(stdout, writeBuffer, sizeof(writeBuffer));
#if 1
// Use the same Encoding of the input. Also use BOM according to input.
typedef AutoUTFOutputStream<unsigned, FileWriteStream> OutputStream; // NEW
OutputStream eos(os, eis.GetType(), eis.HasBOM()); // NEW
PrettyWriter<OutputStream, UTF8<>, AutoUTF<unsigned> > writer(eos); // CHANGED
#else
// You may also use static bound encoding type, such as output to UTF-16LE with BOM
typedef EncodedOutputStream<UTF16LE<>,FileWriteStream> OutputStream; // NEW
OutputStream eos(os, true); // NEW
PrettyWriter<OutputStream, UTF8<>, UTF16LE<> > writer(eos); // CHANGED
#endif
// JSON reader parse from the input stream and let writer generate the output.
//if (!reader.Parse<kParseValidateEncodingFlag>(is, writer)) {
if (!reader.Parse<kParseValidateEncodingFlag>(eis, writer)) { // CHANGED
fprintf(stderr, "\nError(%u): %s\n", static_cast<unsigned>(reader.GetErrorOffset()), GetParseError_En(reader.GetParseErrorCode()));
return 1;
}
return 0;
}

View File

@@ -0,0 +1,78 @@
// Schema Validator example
// The example validates JSON text from stdin with a JSON schema specified in the argument.
#include "rapidjson/error/en.h"
#include "rapidjson/filereadstream.h"
#include "rapidjson/schema.h"
#include "rapidjson/stringbuffer.h"
#include "rapidjson/prettywriter.h"
using namespace rapidjson;
int main(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "Usage: schemavalidator schema.json < input.json\n");
return EXIT_FAILURE;
}
// Read a JSON schema from file into Document
Document d;
char buffer[4096];
{
FILE *fp = fopen(argv[1], "r");
if (!fp) {
printf("Schema file '%s' not found\n", argv[1]);
return -1;
}
FileReadStream fs(fp, buffer, sizeof(buffer));
d.ParseStream(fs);
if (d.HasParseError()) {
fprintf(stderr, "Schema file '%s' is not a valid JSON\n", argv[1]);
fprintf(stderr, "Error(offset %u): %s\n",
static_cast<unsigned>(d.GetErrorOffset()),
GetParseError_En(d.GetParseError()));
fclose(fp);
return EXIT_FAILURE;
}
fclose(fp);
}
// Then convert the Document into SchemaDocument
SchemaDocument sd(d);
// Use reader to parse the JSON in stdin, and forward SAX events to validator
SchemaValidator validator(sd);
Reader reader;
FileReadStream is(stdin, buffer, sizeof(buffer));
if (!reader.Parse(is, validator) && reader.GetParseErrorCode() != kParseErrorTermination) {
// Schema validator error would cause kParseErrorTermination, which will handle it in next step.
fprintf(stderr, "Input is not a valid JSON\n");
fprintf(stderr, "Error(offset %u): %s\n",
static_cast<unsigned>(reader.GetErrorOffset()),
GetParseError_En(reader.GetParseErrorCode()));
}
// Check the validation result
if (validator.IsValid()) {
printf("Input JSON is valid.\n");
return EXIT_SUCCESS;
}
else {
printf("Input JSON is invalid.\n");
StringBuffer sb;
validator.GetInvalidSchemaPointer().StringifyUriFragment(sb);
fprintf(stderr, "Invalid schema: %s\n", sb.GetString());
fprintf(stderr, "Invalid keyword: %s\n", validator.GetInvalidSchemaKeyword());
sb.Clear();
validator.GetInvalidDocumentPointer().StringifyUriFragment(sb);
fprintf(stderr, "Invalid document: %s\n", sb.GetString());
// Detailed violation report is available as a JSON value
sb.Clear();
PrettyWriter<StringBuffer> w(sb);
validator.GetError().Accept(w);
fprintf(stderr, "Error report:\n%s\n", sb.GetString());
return EXIT_FAILURE;
}
}

View File

@@ -0,0 +1,173 @@
// Serialize example
// This example shows writing JSON string with writer directly.
#include "rapidjson/prettywriter.h" // for stringify JSON
#include <cstdio>
#include <string>
#include <vector>
using namespace rapidjson;
class Person {
public:
Person(const std::string& name, unsigned age) : name_(name), age_(age) {}
Person(const Person& rhs) : name_(rhs.name_), age_(rhs.age_) {}
virtual ~Person();
Person& operator=(const Person& rhs) {
name_ = rhs.name_;
age_ = rhs.age_;
return *this;
}
protected:
template <typename Writer>
void Serialize(Writer& writer) const {
// This base class just write out name-value pairs, without wrapping within an object.
writer.String("name");
#if RAPIDJSON_HAS_STDSTRING
writer.String(name_);
#else
writer.String(name_.c_str(), static_cast<SizeType>(name_.length())); // Supplying length of string is faster.
#endif
writer.String("age");
writer.Uint(age_);
}
private:
std::string name_;
unsigned age_;
};
Person::~Person() {
}
class Education {
public:
Education(const std::string& school, double GPA) : school_(school), GPA_(GPA) {}
Education(const Education& rhs) : school_(rhs.school_), GPA_(rhs.GPA_) {}
template <typename Writer>
void Serialize(Writer& writer) const {
writer.StartObject();
writer.String("school");
#if RAPIDJSON_HAS_STDSTRING
writer.String(school_);
#else
writer.String(school_.c_str(), static_cast<SizeType>(school_.length()));
#endif
writer.String("GPA");
writer.Double(GPA_);
writer.EndObject();
}
private:
std::string school_;
double GPA_;
};
class Dependent : public Person {
public:
Dependent(const std::string& name, unsigned age, Education* education = 0) : Person(name, age), education_(education) {}
Dependent(const Dependent& rhs) : Person(rhs), education_(0) { education_ = (rhs.education_ == 0) ? 0 : new Education(*rhs.education_); }
virtual ~Dependent();
Dependent& operator=(const Dependent& rhs) {
if (this == &rhs)
return *this;
delete education_;
education_ = (rhs.education_ == 0) ? 0 : new Education(*rhs.education_);
return *this;
}
template <typename Writer>
void Serialize(Writer& writer) const {
writer.StartObject();
Person::Serialize(writer);
writer.String("education");
if (education_)
education_->Serialize(writer);
else
writer.Null();
writer.EndObject();
}
private:
Education *education_;
};
Dependent::~Dependent() {
delete education_;
}
class Employee : public Person {
public:
Employee(const std::string& name, unsigned age, bool married) : Person(name, age), dependents_(), married_(married) {}
Employee(const Employee& rhs) : Person(rhs), dependents_(rhs.dependents_), married_(rhs.married_) {}
virtual ~Employee();
Employee& operator=(const Employee& rhs) {
static_cast<Person&>(*this) = rhs;
dependents_ = rhs.dependents_;
married_ = rhs.married_;
return *this;
}
void AddDependent(const Dependent& dependent) {
dependents_.push_back(dependent);
}
template <typename Writer>
void Serialize(Writer& writer) const {
writer.StartObject();
Person::Serialize(writer);
writer.String("married");
writer.Bool(married_);
writer.String(("dependents"));
writer.StartArray();
for (std::vector<Dependent>::const_iterator dependentItr = dependents_.begin(); dependentItr != dependents_.end(); ++dependentItr)
dependentItr->Serialize(writer);
writer.EndArray();
writer.EndObject();
}
private:
std::vector<Dependent> dependents_;
bool married_;
};
Employee::~Employee() {
}
int main(int, char*[]) {
std::vector<Employee> employees;
employees.push_back(Employee("Milo YIP", 34, true));
employees.back().AddDependent(Dependent("Lua YIP", 3, new Education("Happy Kindergarten", 3.5)));
employees.back().AddDependent(Dependent("Mio YIP", 1));
employees.push_back(Employee("Percy TSE", 30, false));
StringBuffer sb;
PrettyWriter<StringBuffer> writer(sb);
writer.StartArray();
for (std::vector<Employee>::const_iterator employeeItr = employees.begin(); employeeItr != employees.end(); ++employeeItr)
employeeItr->Serialize(writer);
writer.EndArray();
puts(sb.GetString());
return 0;
}

View File

@@ -0,0 +1,29 @@
// JSON simple example
// This example does not handle errors.
#include "rapidjson/document.h"
#include "rapidjson/writer.h"
#include "rapidjson/stringbuffer.h"
#include <iostream>
using namespace rapidjson;
int main() {
// 1. Parse a JSON string into DOM.
const char* json = "{\"project\":\"rapidjson\",\"stars\":10}";
Document d;
d.Parse(json);
// 2. Modify it by DOM.
Value& s = d["stars"];
s.SetInt(s.GetInt() + 1);
// 3. Stringify the DOM
StringBuffer buffer;
Writer<StringBuffer> writer(buffer);
d.Accept(writer);
// Output {"project":"rapidjson","stars":11}
std::cout << buffer.GetString() << std::endl;
return 0;
}

View File

@@ -0,0 +1,53 @@
#include "rapidjson/reader.h"
#include <iostream>
#include <sstream>
using namespace rapidjson;
using namespace std;
// If you can require C++11, you could use std::to_string here
template <typename T> std::string stringify(T x) {
std::stringstream ss;
ss << x;
return ss.str();
}
struct MyHandler {
const char* type;
std::string data;
MyHandler() : type(), data() {}
bool Null() { type = "Null"; data.clear(); return true; }
bool Bool(bool b) { type = "Bool:"; data = b? "true": "false"; return true; }
bool Int(int i) { type = "Int:"; data = stringify(i); return true; }
bool Uint(unsigned u) { type = "Uint:"; data = stringify(u); return true; }
bool Int64(int64_t i) { type = "Int64:"; data = stringify(i); return true; }
bool Uint64(uint64_t u) { type = "Uint64:"; data = stringify(u); return true; }
bool Double(double d) { type = "Double:"; data = stringify(d); return true; }
bool RawNumber(const char* str, SizeType length, bool) { type = "Number:"; data = std::string(str, length); return true; }
bool String(const char* str, SizeType length, bool) { type = "String:"; data = std::string(str, length); return true; }
bool StartObject() { type = "StartObject"; data.clear(); return true; }
bool Key(const char* str, SizeType length, bool) { type = "Key:"; data = std::string(str, length); return true; }
bool EndObject(SizeType memberCount) { type = "EndObject:"; data = stringify(memberCount); return true; }
bool StartArray() { type = "StartArray"; data.clear(); return true; }
bool EndArray(SizeType elementCount) { type = "EndArray:"; data = stringify(elementCount); return true; }
private:
MyHandler(const MyHandler& noCopyConstruction);
MyHandler& operator=(const MyHandler& noAssignment);
};
int main() {
const char json[] = " { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } ";
MyHandler handler;
Reader reader;
StringStream ss(json);
reader.IterativeParseInit();
while (!reader.IterativeParseComplete()) {
reader.IterativeParseNext<kParseDefaultFlags>(ss, handler);
cout << handler.type << handler.data << endl;
}
return 0;
}

View File

@@ -0,0 +1,42 @@
#include "rapidjson/reader.h"
#include <iostream>
using namespace rapidjson;
using namespace std;
struct MyHandler {
bool Null() { cout << "Null()" << endl; return true; }
bool Bool(bool b) { cout << "Bool(" << boolalpha << b << ")" << endl; return true; }
bool Int(int i) { cout << "Int(" << i << ")" << endl; return true; }
bool Uint(unsigned u) { cout << "Uint(" << u << ")" << endl; return true; }
bool Int64(int64_t i) { cout << "Int64(" << i << ")" << endl; return true; }
bool Uint64(uint64_t u) { cout << "Uint64(" << u << ")" << endl; return true; }
bool Double(double d) { cout << "Double(" << d << ")" << endl; return true; }
bool RawNumber(const char* str, SizeType length, bool copy) {
cout << "Number(" << str << ", " << length << ", " << boolalpha << copy << ")" << endl;
return true;
}
bool String(const char* str, SizeType length, bool copy) {
cout << "String(" << str << ", " << length << ", " << boolalpha << copy << ")" << endl;
return true;
}
bool StartObject() { cout << "StartObject()" << endl; return true; }
bool Key(const char* str, SizeType length, bool copy) {
cout << "Key(" << str << ", " << length << ", " << boolalpha << copy << ")" << endl;
return true;
}
bool EndObject(SizeType memberCount) { cout << "EndObject(" << memberCount << ")" << endl; return true; }
bool StartArray() { cout << "StartArray()" << endl; return true; }
bool EndArray(SizeType elementCount) { cout << "EndArray(" << elementCount << ")" << endl; return true; }
};
int main() {
const char json[] = " { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } ";
MyHandler handler;
Reader reader;
StringStream ss(json);
reader.Parse(ss, handler);
return 0;
}

View File

@@ -0,0 +1,36 @@
#include "rapidjson/writer.h"
#include "rapidjson/stringbuffer.h"
#include <iostream>
using namespace rapidjson;
using namespace std;
int main() {
StringBuffer s;
Writer<StringBuffer> writer(s);
writer.StartObject(); // Between StartObject()/EndObject(),
writer.Key("hello"); // output a key,
writer.String("world"); // follow by a value.
writer.Key("t");
writer.Bool(true);
writer.Key("f");
writer.Bool(false);
writer.Key("n");
writer.Null();
writer.Key("i");
writer.Uint(123);
writer.Key("pi");
writer.Double(3.1416);
writer.Key("a");
writer.StartArray(); // Between StartArray()/EndArray(),
for (unsigned i = 0; i < 4; i++)
writer.Uint(i); // all values are elements of the array.
writer.EndArray();
writer.EndObject();
// {"hello":"world","t":true,"f":false,"n":null,"i":123,"pi":3.1416,"a":[0,1,2,3]}
cout << s.GetString() << endl;
return 0;
}

View File

@@ -0,0 +1,62 @@
#include "rapidjson/document.h"
#include "rapidjson/filewritestream.h"
#include <rapidjson/prettywriter.h>
#include <algorithm>
#include <iostream>
using namespace rapidjson;
using namespace std;
static void printIt(const Value &doc) {
char writeBuffer[65536];
FileWriteStream os(stdout, writeBuffer, sizeof(writeBuffer));
PrettyWriter<FileWriteStream> writer(os);
doc.Accept(writer);
cout << endl;
}
struct NameComparator {
bool operator()(const Value::Member &lhs, const Value::Member &rhs) const {
return (strcmp(lhs.name.GetString(), rhs.name.GetString()) < 0);
}
};
int main() {
Document d(kObjectType);
Document::AllocatorType &allocator = d.GetAllocator();
d.AddMember("zeta", Value().SetBool(false), allocator);
d.AddMember("gama", Value().SetString("test string", allocator), allocator);
d.AddMember("delta", Value().SetInt(123), allocator);
d.AddMember("alpha", Value(kArrayType).Move(), allocator);
printIt(d);
/*
{
"zeta": false,
"gama": "test string",
"delta": 123,
"alpha": []
}
*/
// C++11 supports std::move() of Value so it always have no problem for std::sort().
// Some C++03 implementations of std::sort() requires copy constructor which causes compilation error.
// Needs a sorting function only depends on std::swap() instead.
#if __cplusplus >= 201103L || (!defined(__GLIBCXX__) && (!defined(_MSC_VER) || _MSC_VER >= 1900))
std::sort(d.MemberBegin(), d.MemberEnd(), NameComparator());
printIt(d);
/*
{
"alpha": [],
"delta": 123,
"gama": "test string",
"zeta": false
}
*/
#endif
}

View File

@@ -0,0 +1,151 @@
// Hello World example
// This example shows basic usage of DOM-style API.
#include "rapidjson/document.h" // rapidjson's DOM-style API
#include "rapidjson/prettywriter.h" // for stringify JSON
#include <cstdio>
using namespace rapidjson;
using namespace std;
int main(int, char*[]) {
////////////////////////////////////////////////////////////////////////////
// 1. Parse a JSON text string to a document.
const char json[] = " { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } ";
printf("Original JSON:\n %s\n", json);
Document document; // Default template parameter uses UTF8 and MemoryPoolAllocator.
#if 0
// "normal" parsing, decode strings to new buffers. Can use other input stream via ParseStream().
if (document.Parse(json).HasParseError())
return 1;
#else
// In-situ parsing, decode strings directly in the source string. Source must be string.
char buffer[sizeof(json)];
memcpy(buffer, json, sizeof(json));
if (document.ParseInsitu(buffer).HasParseError())
return 1;
#endif
printf("\nParsing to document succeeded.\n");
////////////////////////////////////////////////////////////////////////////
// 2. Access values in document.
printf("\nAccess values in document:\n");
assert(document.IsObject()); // Document is a JSON value represents the root of DOM. Root can be either an object or array.
assert(document.HasMember("hello"));
assert(document["hello"].IsString());
printf("hello = %s\n", document["hello"].GetString());
// Since version 0.2, you can use single lookup to check the existing of member and its value:
Value::MemberIterator hello = document.FindMember("hello");
assert(hello != document.MemberEnd());
assert(hello->value.IsString());
assert(strcmp("world", hello->value.GetString()) == 0);
(void)hello;
assert(document["t"].IsBool()); // JSON true/false are bool. Can also uses more specific function IsTrue().
printf("t = %s\n", document["t"].GetBool() ? "true" : "false");
assert(document["f"].IsBool());
printf("f = %s\n", document["f"].GetBool() ? "true" : "false");
printf("n = %s\n", document["n"].IsNull() ? "null" : "?");
assert(document["i"].IsNumber()); // Number is a JSON type, but C++ needs more specific type.
assert(document["i"].IsInt()); // In this case, IsUint()/IsInt64()/IsUint64() also return true.
printf("i = %d\n", document["i"].GetInt()); // Alternative (int)document["i"]
assert(document["pi"].IsNumber());
assert(document["pi"].IsDouble());
printf("pi = %g\n", document["pi"].GetDouble());
{
const Value& a = document["a"]; // Using a reference for consecutive access is handy and faster.
assert(a.IsArray());
for (SizeType i = 0; i < a.Size(); i++) // rapidjson uses SizeType instead of size_t.
printf("a[%d] = %d\n", i, a[i].GetInt());
int y = a[0].GetInt();
(void)y;
// Iterating array with iterators
printf("a = ");
for (Value::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr)
printf("%d ", itr->GetInt());
printf("\n");
}
// Iterating object members
static const char* kTypeNames[] = { "Null", "False", "True", "Object", "Array", "String", "Number" };
for (Value::ConstMemberIterator itr = document.MemberBegin(); itr != document.MemberEnd(); ++itr)
printf("Type of member %s is %s\n", itr->name.GetString(), kTypeNames[itr->value.GetType()]);
////////////////////////////////////////////////////////////////////////////
// 3. Modify values in document.
// Change i to a bigger number
{
uint64_t f20 = 1; // compute factorial of 20
for (uint64_t j = 1; j <= 20; j++)
f20 *= j;
document["i"] = f20; // Alternate form: document["i"].SetUint64(f20)
assert(!document["i"].IsInt()); // No longer can be cast as int or uint.
}
// Adding values to array.
{
Value& a = document["a"]; // This time we uses non-const reference.
Document::AllocatorType& allocator = document.GetAllocator();
for (int i = 5; i <= 10; i++)
a.PushBack(i, allocator); // May look a bit strange, allocator is needed for potentially realloc. We normally uses the document's.
// Fluent API
a.PushBack("Lua", allocator).PushBack("Mio", allocator);
}
// Making string values.
// This version of SetString() just store the pointer to the string.
// So it is for literal and string that exists within value's life-cycle.
{
document["hello"] = "rapidjson"; // This will invoke strlen()
// Faster version:
// document["hello"].SetString("rapidjson", 9);
}
// This version of SetString() needs an allocator, which means it will allocate a new buffer and copy the the string into the buffer.
Value author;
{
char buffer2[10];
int len = sprintf(buffer2, "%s %s", "Milo", "Yip"); // synthetic example of dynamically created string.
author.SetString(buffer2, static_cast<SizeType>(len), document.GetAllocator());
// Shorter but slower version:
// document["hello"].SetString(buffer, document.GetAllocator());
// Constructor version:
// Value author(buffer, len, document.GetAllocator());
// Value author(buffer, document.GetAllocator());
memset(buffer2, 0, sizeof(buffer2)); // For demonstration purpose.
}
// Variable 'buffer' is unusable now but 'author' has already made a copy.
document.AddMember("author", author, document.GetAllocator());
assert(author.IsNull()); // Move semantic for assignment. After this variable is assigned as a member, the variable becomes null.
////////////////////////////////////////////////////////////////////////////
// 4. Stringify JSON
printf("\nModified JSON with reformatting:\n");
StringBuffer sb;
PrettyWriter<StringBuffer> writer(sb);
document.Accept(writer); // Accept() traverses the DOM and generates Handler events.
puts(sb.GetString());
return 0;
}