Bump rapidjson version (#6906)
This commit is contained in:
committed by
GitHub
parent
667fd198ac
commit
163a2cfe3c
+7
-3
@@ -10,6 +10,7 @@ set(EXAMPLES
|
||||
filterkey
|
||||
filterkeydom
|
||||
jsonx
|
||||
lookaheadparser
|
||||
messagereader
|
||||
parsebyparts
|
||||
pretty
|
||||
@@ -18,19 +19,22 @@ set(EXAMPLES
|
||||
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 -Werror -Wall -Wextra -Weffc++ -Wswitch-default")
|
||||
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -Weffc++ -Wswitch-default -Wfloat-equal -Wimplicit-fallthrough -Weverything")
|
||||
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()
|
||||
|
||||
+292
@@ -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
|
||||
+145
@@ -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__
|
||||
@@ -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();
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// JSON to JSONx conversion exmaple, using SAX API.
|
||||
// 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,
|
||||
|
||||
@@ -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
|
||||
@@ -21,12 +21,15 @@ public:
|
||||
AsyncDocumentParser(Document& d)
|
||||
: stream_(*this)
|
||||
, d_(d)
|
||||
, parseThread_(&AsyncDocumentParser::Parse, this)
|
||||
, 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())
|
||||
@@ -140,7 +143,7 @@ int main() {
|
||||
AsyncDocumentParser<> parser(d);
|
||||
|
||||
const char json1[] = " { \"hello\" : \"world\", \"t\" : tr";
|
||||
//const char json1[] = " { \"hello\" : \"world\", \"t\" : trX"; // Fot test parsing error
|
||||
//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] } ";
|
||||
|
||||
|
||||
@@ -2,13 +2,132 @@
|
||||
|
||||
// The example validates JSON text from stdin with a JSON schema specified in the argument.
|
||||
|
||||
#define RAPIDJSON_HAS_STDSTRING 1
|
||||
|
||||
#include "rapidjson/error/en.h"
|
||||
#include "rapidjson/filereadstream.h"
|
||||
#include "rapidjson/schema.h"
|
||||
#include "rapidjson/stringbuffer.h"
|
||||
#include "rapidjson/prettywriter.h"
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
typedef GenericValue<UTF8<>, CrtAllocator > ValueType;
|
||||
|
||||
// Forward ref
|
||||
static void CreateErrorMessages(const ValueType& errors, size_t depth, const char* context);
|
||||
|
||||
// Convert GenericValue to std::string
|
||||
static std::string GetString(const ValueType& val) {
|
||||
std::ostringstream s;
|
||||
if (val.IsString())
|
||||
s << val.GetString();
|
||||
else if (val.IsDouble())
|
||||
s << val.GetDouble();
|
||||
else if (val.IsUint())
|
||||
s << val.GetUint();
|
||||
else if (val.IsInt())
|
||||
s << val.GetInt();
|
||||
else if (val.IsUint64())
|
||||
s << val.GetUint64();
|
||||
else if (val.IsInt64())
|
||||
s << val.GetInt64();
|
||||
else if (val.IsBool() && val.GetBool())
|
||||
s << "true";
|
||||
else if (val.IsBool())
|
||||
s << "false";
|
||||
else if (val.IsFloat())
|
||||
s << val.GetFloat();
|
||||
return s.str();
|
||||
}
|
||||
|
||||
// Create the error message for a named error
|
||||
// The error object can either be empty or contain at least member properties:
|
||||
// {"errorCode": <code>, "instanceRef": "<pointer>", "schemaRef": "<pointer>" }
|
||||
// Additional properties may be present for use as inserts.
|
||||
// An "errors" property may be present if there are child errors.
|
||||
static void HandleError(const char* errorName, const ValueType& error, size_t depth, const char* context) {
|
||||
if (!error.ObjectEmpty()) {
|
||||
// Get error code and look up error message text (English)
|
||||
int code = error["errorCode"].GetInt();
|
||||
std::string message(GetValidateError_En(static_cast<ValidateErrorCode>(code)));
|
||||
// For each member property in the error, see if its name exists as an insert in the error message and if so replace with the stringified property value
|
||||
// So for example - "Number '%actual' is not a multiple of the 'multipleOf' value '%expected'." - we would expect "actual" and "expected" members.
|
||||
for (ValueType::ConstMemberIterator insertsItr = error.MemberBegin();
|
||||
insertsItr != error.MemberEnd(); ++insertsItr) {
|
||||
std::string insertName("%");
|
||||
insertName += insertsItr->name.GetString(); // eg "%actual"
|
||||
size_t insertPos = message.find(insertName);
|
||||
if (insertPos != std::string::npos) {
|
||||
std::string insertString("");
|
||||
const ValueType &insert = insertsItr->value;
|
||||
if (insert.IsArray()) {
|
||||
// Member is an array so create comma-separated list of items for the insert string
|
||||
for (ValueType::ConstValueIterator itemsItr = insert.Begin(); itemsItr != insert.End(); ++itemsItr) {
|
||||
if (itemsItr != insert.Begin()) insertString += ",";
|
||||
insertString += GetString(*itemsItr);
|
||||
}
|
||||
} else {
|
||||
insertString += GetString(insert);
|
||||
}
|
||||
message.replace(insertPos, insertName.length(), insertString);
|
||||
}
|
||||
}
|
||||
// Output error message, references, context
|
||||
std::string indent(depth * 2, ' ');
|
||||
std::cout << indent << "Error Name: " << errorName << std::endl;
|
||||
std::cout << indent << "Message: " << message.c_str() << std::endl;
|
||||
std::cout << indent << "Instance: " << error["instanceRef"].GetString() << std::endl;
|
||||
std::cout << indent << "Schema: " << error["schemaRef"].GetString() << std::endl;
|
||||
if (depth > 0) std::cout << indent << "Context: " << context << std::endl;
|
||||
std::cout << std::endl;
|
||||
|
||||
// If child errors exist, apply the process recursively to each error structure.
|
||||
// This occurs for "oneOf", "allOf", "anyOf" and "dependencies" errors, so pass the error name as context.
|
||||
if (error.HasMember("errors")) {
|
||||
depth++;
|
||||
const ValueType &childErrors = error["errors"];
|
||||
if (childErrors.IsArray()) {
|
||||
// Array - each item is an error structure - example
|
||||
// "anyOf": {"errorCode": ..., "errors":[{"pattern": {"errorCode\": ...\"}}, {"pattern": {"errorCode\": ...}}]
|
||||
for (ValueType::ConstValueIterator errorsItr = childErrors.Begin();
|
||||
errorsItr != childErrors.End(); ++errorsItr) {
|
||||
CreateErrorMessages(*errorsItr, depth, errorName);
|
||||
}
|
||||
} else if (childErrors.IsObject()) {
|
||||
// Object - each member is an error structure - example
|
||||
// "dependencies": {"errorCode": ..., "errors": {"address": {"required": {"errorCode": ...}}, "name": {"required": {"errorCode": ...}}}
|
||||
for (ValueType::ConstMemberIterator propsItr = childErrors.MemberBegin();
|
||||
propsItr != childErrors.MemberEnd(); ++propsItr) {
|
||||
CreateErrorMessages(propsItr->value, depth, errorName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create error message for all errors in an error structure
|
||||
// Context is used to indicate whether the error structure has a parent 'dependencies', 'allOf', 'anyOf' or 'oneOf' error
|
||||
static void CreateErrorMessages(const ValueType& errors, size_t depth = 0, const char* context = 0) {
|
||||
// Each member property contains one or more errors of a given type
|
||||
for (ValueType::ConstMemberIterator errorTypeItr = errors.MemberBegin(); errorTypeItr != errors.MemberEnd(); ++errorTypeItr) {
|
||||
const char* errorName = errorTypeItr->name.GetString();
|
||||
const ValueType& errorContent = errorTypeItr->value;
|
||||
if (errorContent.IsArray()) {
|
||||
// Member is an array where each item is an error - eg "type": [{"errorCode": ...}, {"errorCode": ...}]
|
||||
for (ValueType::ConstValueIterator contentItr = errorContent.Begin(); contentItr != errorContent.End(); ++contentItr) {
|
||||
HandleError(errorName, *contentItr, depth, context);
|
||||
}
|
||||
} else if (errorContent.IsObject()) {
|
||||
// Member is an object which is a single error - eg "type": {"errorCode": ... }
|
||||
HandleError(errorName, errorContent, depth, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "Usage: schemavalidator schema.json < input.json\n");
|
||||
@@ -64,9 +183,17 @@ int main(int argc, char *argv[]) {
|
||||
validator.GetInvalidSchemaPointer().StringifyUriFragment(sb);
|
||||
fprintf(stderr, "Invalid schema: %s\n", sb.GetString());
|
||||
fprintf(stderr, "Invalid keyword: %s\n", validator.GetInvalidSchemaKeyword());
|
||||
fprintf(stderr, "Invalid code: %d\n", validator.GetInvalidSchemaCode());
|
||||
fprintf(stderr, "Invalid message: %s\n", GetValidateError_En(validator.GetInvalidSchemaCode()));
|
||||
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());
|
||||
CreateErrorMessages(validator.GetError());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
#include "rapidjson/document.h"
|
||||
#include "rapidjson/filereadstream.h"
|
||||
#include "rapidjson/pointer.h"
|
||||
#include "rapidjson/stringbuffer.h"
|
||||
#include <iostream>
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
void traverse(const Value& v, const Pointer& p) {
|
||||
StringBuffer sb;
|
||||
p.Stringify(sb);
|
||||
std::cout << sb.GetString() << std::endl;
|
||||
|
||||
switch (v.GetType()) {
|
||||
case kArrayType:
|
||||
for (SizeType i = 0; i != v.Size(); ++i)
|
||||
traverse(v[i], p.Append(i));
|
||||
break;
|
||||
case kObjectType:
|
||||
for (Value::ConstMemberIterator m = v.MemberBegin(); m != v.MemberEnd(); ++m)
|
||||
traverse(m->value, p.Append(m->name.GetString(), m->name.GetStringLength()));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int, char*[]) {
|
||||
char readBuffer[65536];
|
||||
FileReadStream is(stdin, readBuffer, sizeof(readBuffer));
|
||||
|
||||
Document d;
|
||||
d.ParseStream(is);
|
||||
|
||||
Pointer root;
|
||||
traverse(d, root);
|
||||
|
||||
return 0;
|
||||
}
|
||||
+1
-1
@@ -57,7 +57,7 @@ int main(int, char*[]) {
|
||||
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.
|
||||
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());
|
||||
|
||||
Reference in New Issue
Block a user