Here’s what I came up with for an initial JSON -> cocos2d::Value using rapidjson (included as part of cocostudio lib). It’s a first pass so there are possibly unnecessary copies or even memory leak, or bug in the conversion. But it’s working with a couple simple .json and .plist comparison tests. Since I’ve used ValueMap and ValueVector extensively within one project since it was a migration from 2.x to 3.x and initially used plists this works for that project. I’m not sure it’ll be useful for a brand new project which could use rapidjson directly instead of cocos2d::Value as well as using standard data c++11 data types and containers. Anyway, here’s my current util class.
.h
#pragma once
#include <base/CCValue.h>
#include <json/document.h>
class STValueMapFromJSON
{
public:
static cocos2d::Value parseValueFromJsonValue(const rapidjson::Value& jvalue);
static cocos2d::ValueMap getValueMapFromJsonFile(const std::string& filename);
static cocos2d::ValueVector getValueVectorFromJsonFile(const std::string& filename);
};
.cpp
#include "STValueMapFromJSON.h"
#include <json/rapidjson.h>
#include <cocos2d.h>
#include <cocostudio/DictionaryHelper.h>
//USING_NS_CC;
//using namespace cocostudio;
// TODO: add any necessary 'const', 'const' & references, or error checking
cocos2d::Value STValueMapFromJSON::parseValueFromJsonValue(const rapidjson::Value& jvalue)
{
// parse by type
auto t = jvalue.GetType();
if(t == rapidjson::Type::kNullType)
{
// don't add anything
return cocos2d::Value();
}
if(t == rapidjson::Type::kFalseType) {
return cocos2d::Value(false);
}
if(t == rapidjson::Type::kTrueType) {
return cocos2d::Value(true);
}
if(t == rapidjson::Type::kStringType) {
return cocos2d::Value(jvalue.GetString());
}
if(t == rapidjson::Type::kNumberType) {
if(jvalue.IsDouble()) {
return cocos2d::Value(jvalue.GetDouble());
} else if(jvalue.IsUint()) {
int temp = int(jvalue.GetUint());
return cocos2d::Value(temp);
} else if(jvalue.IsInt()) {
return cocos2d::Value(jvalue.GetInt());
}
}
if(t == rapidjson::Type::kObjectType) {
cocos2d::ValueMap dict;
for (rapidjson::Value::ConstMemberIterator itr = jvalue.MemberonBegin(); itr != jvalue.MemberonEnd(); ++itr)
{
auto jsonKey = itr->name.GetString();
auto el = parseValueFromJsonValue(itr->value);
dict[jsonKey] = el;
}
return cocos2d::Value(dict);
}
if(t == rapidjson::Type::kArrayType) {
cocos2d::ValueVector arr;
// rapidjson uses SizeType instead of size_t.
for (rapidjson::SizeType i = 0; i < jvalue.Size(); i++) {
auto el = parseValueFromJsonValue(jvalue[i]);
arr.push_back(el);
}
return cocos2d::Value(arr);
}
// none
return cocos2d::Value();
}
cocos2d::ValueMap STValueMapFromJSON::getValueMapFromJsonFile(const std::string& filename)
{
auto content = cocos2d::FileUtils::getInstance()->getStringFromFile(filename);
rapidjson::Document doc;
doc.Parse<0>(content.c_str());
if (! doc.HasParseError())
{
// check that root is object not array
auto val = parseValueFromJsonValue(doc);
if(val.getType() == cocos2d::Value::Type::MAP) {
return val.asValueMap();
}
CCLOGERROR("JSON wasn't a ValueMap/Dict");
}
CCLOG("JSON Parse Error: %s\n", doc.GetParseError());
cocos2d::ValueMap ret;
return ret;
}
cocos2d::ValueVector STValueMapFromJSON::getValueVectorFromJsonFile(const std::string& filename)
{
auto content = cocos2d::FileUtils::getInstance()->getStringFromFile(filename);
rapidjson::Document doc;
doc.Parse<0>(content.c_str());
if (! doc.HasParseError())
{
// check that root is object not array
auto val = parseValueFromJsonValue(doc);
if(val.getType() == cocos2d::Value::Type::VECTOR) {
return val.asValueVector();
}
CCLOGERROR("JSON wasn't a ValueVector/Array");
}
CCLOG("JSON Parse Error: %s\n", doc.GetParseError());
cocos2d::ValueVector ret;
return ret;
}