Reputation: 169
I want to be able to create the following JSON output using rapidJSON
{
"year": 2013,
"league": "national",
"teams": [
{
"teamname": "reds",
"teamcity": "cincinnati",
"roster": [
{
"playername": "john",
"position": "catcher"
},
{
"playername": "joe",
"position": "pitcher"
}
]
}
]
}
This is valid JSON... Verified at JSONLint.com I know how to create a document and use AddMember to add "year" and "league".
I can not figure out and have not seen any examples of how to add an array that has a structure like "teams" or "roster"
How does one add "teams" which is an array of structures? Any help or point me to an example would be great.
Upvotes: 16
Views: 34361
Reputation: 931
Pointers are the nicest way to build objects with rapidjson. You basically give it a path and set the value at that path. It allows convenient nesting because the path is created if it doesn't exist.
The fmt library, which has recently been adopted by the c++ standard library as std::format, is very useful for helping us create the paths.
Setup
#include <string>
#include <vector>
#define FMT_HEADER_ONLY
#include <fmt/format.h>
#include <rapidjson/document.h>
#include <rapidjson/pointer.h>
#include <rapidjson/stringbuffer.h>
#include <rapidjson/writer.h>
using namespace rapidjson;
struct Player {
std::string playername;
std::string position;
};
struct Team {
std::string teamname;
std::string teamcity;
std::vector<Player> roster;
};
std::vector<Team> teams = {
{"reds", "cincinnati", {{"john", "catcher"}, {"joe", "pitcher"}}}
};
Rapidjson pointer paths take a number to be an array index (if the number is not a key at the given path). We can take advantage of that by using the index of the vector as we iterate old school, while all the array creation is handled for us.
Main
Document doc;
Pointer("/year").Set(doc, 2013);
Pointer("/league").Set(doc, "national");
for (size_t i = 0; i < teams.size(); ++i) {
auto team_name = fmt::format("/teams/{}/teamname", i);
auto team_city = fmt::format("/teams/{}/teamcity", i);
Pointer(team_name.data()).Set(doc, teams[i].teamname.data());
Pointer(team_city.data()).Set(doc, teams[i].teamcity.data());
for (size_t j = 0; j < teams[i].roster.size(); ++j) {
auto name = fmt::format("/teams/{}/roster/{}/playername", i, j);
auto position = fmt::format("/teams/{}/roster/{}/position", i, j);
Pointer(name.data()).Set(doc, teams[i].roster[j].playername.data());
Pointer(position.data()).Set(doc, teams[i].roster[j].position.data());
}
}
Finally, get JSON string from Document
StringBuffer buffer;
Writer<StringBuffer> writer(buffer);
doc.Accept(writer);
auto json_str = buffer.GetString();
Upvotes: 0
Reputation: 915
rapidjson::StringBuffer s;
rapidjson::Writer<rapidjson::StringBuffer> writer(s);
writer.StartObject();
std::string year("year");
writer.String(year.c_str(), static_cast<rapidjson::SizeType>(year.length()));
writer.Int(2013);
std::string league("league");
writer.String(league.c_str(), static_cast<rapidjson::SizeType>(league.length()));
std::string national("national");
writer.String(national.c_str(), static_cast<rapidjson::SizeType>(national.length()));
std::string teams("teams");
writer.String(teams.c_str(), static_cast<rapidjson::SizeType>(teams.length()));
writer.StartArray();
writer.StartObject();
std::string teamname("teamname");
writer.String(teamname.c_str(), static_cast<rapidjson::SizeType>(teamname.length()));
std::string reds("reds");
writer.String(reds.c_str(), static_cast<rapidjson::SizeType>(reds.length()));
std::string teamcity("teamcity");
writer.String(teamcity.c_str(), static_cast<rapidjson::SizeType>(teamcity.length()));
std::string cincinnati("cincinnati");
writer.String(cincinnati.c_str(), static_cast<rapidjson::SizeType>(cincinnati.length()));
std::string roster("roster");
writer.String(roster.c_str(), static_cast<rapidjson::SizeType>(roster.length()));
writer.StartArray();
writer.StartObject();
std::string playername("playername");
writer.String(playername.c_str(), static_cast<rapidjson::SizeType>(playername.length()));
std::string john("john");
writer.String(john.c_str(), static_cast<rapidjson::SizeType>(john.length()));
std::string position("position");
writer.String(position.c_str(), static_cast<rapidjson::SizeType>(position.length()));
std::string catcher("catcher");
writer.String(catcher.c_str(), static_cast<rapidjson::SizeType>(catcher.length()));
writer.EndObject();
// can add one more object in the same manner
// with player name and position
writer.EndArray();
writer.EndObject();
writer.EndArray();
writer.EndObject();
s.GetString();
Upvotes: 4
Reputation: 121
In Vs2012/Rapidjson Version 0.1, following statement gets unreadable code when output document from StringBuffer.
objValue.AddMember("position", (*iter)->Position().c_str(), allocator);
after a few hours dig, i figured out how to do it in a correctly way.
Value tmp;
tmp.SetString( (*iter)->Position().c_str(), allocator);
objValue.AddMember("position", tmp, allocator);
here is a tutorial: http://miloyip.github.io/rapidjson/md_doc_tutorial.html
Upvotes: 12
Reputation: 981
Lets assume we have a std::vector roster containing PlayerName() and Postion() accessor functions on the Roster class that return std::string&.
rapidjson::Document jsonDoc;
jsonDoc.SetObject();
rapidjson::Value myArray(rapidjson::kArrayType);
rapidjson::Document::AllocatorType& allocator = jsonDoc.GetAllocator();
std::vector<Roster*>::iterator iter = roster.begin();
std::vector<Roster*>::iterator eiter = roster.end();
for (; iter != eiter; ++iter)
{
rapidjson::Value objValue;
objValue.SetObject();
objValue.AddMember("playername", (*iter)->PlayerName().c_str(), allocator);
objValue.AddMember("position", (*iter)->Position().c_str(), allocator);
myArray.PushBack(objValue, allocator);
}
jsonDoc.AddMember("array", myArray, allocator);
rapidjson::StringBuffer strbuf;
rapidjson::Writer<rapidjson::StringBuffer> writer(strbuf);
jsonDoc.Accept(writer);
const char *jsonString = strbuf.GetString(); // to examine the encoding...
This will get you an array of structures in the document. All you should need to do to get the rest of the structure is to nest rapidjson objects within each other and use AddMember() to build your complex object tree. Hope this helps.
Upvotes: 67