#CCObjectからJSONを作成します(cocos2d-x ver2.2.1)
前回はJSONをパースする方法を投稿したので、今回はその逆でCCObjectからJSONを作成する方法を投稿します。
折角cocos2d-xを利用しているのだからCCObjectからJSONを作れたら良いなと思い検索していたら、下記の記事を見つけました。
CCObjectの情報を出力する
上記の記事を参考に、すぐにCCLogで出力するのではなくstreamに溜め込んで返すような感じにしています。
対応しているのはCCString、CCInteger、CCFloat、CCBool、CCArray、CCDictionaryに対応しており、入れ子構造にも対応している設計になっています。
尚、出力されたJSONをCCLogで表示すると中身がちゃんと入っているか確認出来るので、CCObjectの簡易オブジェクトビューアとしても利用出来ると思います。
#define OutputCCObject( obj ) ( outputObject( obj , "") )
const char* outputObject(CCObject* obj, const char* key);
inline const char* outputArray(CCArray* array)
{
std::ostringstream stream;
stream << "[";
for(int i = 0 ; i < array->count(); ++i)
{
CCObject* value = array->objectAtIndex(i);
stream << outputObject(value, "");
if(i != array->count() - 1) {
stream << ",";
}
}
stream << "]";
return stream.str().c_str();
}
inline const char* outputDictionary(CCDictionary* dictionary)
{
std::ostringstream stream;
stream << "{";
CCArray* allKeys = dictionaryAllKeys(dictionary);
CCObject* obj;
int i = 0;
CCARRAY_FOREACH(allKeys, obj)
{
CCString* key = (CCString*)obj;
CCObject* value = dictionary->objectForKey(key->getCString());
stream << outputObject(value, key->getCString());
if(i++ != allKeys->count() - 1) {
stream << ",";
}
}
delete allKeys;
stream << "}";
return stream.str().c_str();
}
inline const char* outputObject(CCObject* obj, const char* key)
{
std::ostringstream stream;
std::ostringstream initialStream;
if(strlen(key) != 0)
{
initialStream << "\"" << key << "\":";
}
if(typeid(*obj) == typeid(CCString))
{
stream << initialStream.str() << "\"" << ((CCString*)obj)->getCString() << "\"";
}
else if(typeid(*obj) == typeid(CCInteger))
{
stream << initialStream.str() << ((CCInteger*)obj)->getValue();
}
else if(typeid(*obj) == typeid(CCFloat))
{
stream << initialStream.str() << ((CCFloat*)obj)->getValue();
}
else if(typeid(*obj) == typeid(CCBool))
{
if( ((CCBool*)obj)->getValue())
{
stream << initialStream.str() << "true";
} else {
stream << initialStream.str() << "false";
}
}
else if(typeid(*obj) == typeid(CCArray))
{
stream << initialStream.str() << outputArray((CCArray*)obj);
}
else if(typeid(*obj) == typeid(CCDictionary))
{
stream << initialStream.str() << outputDictionary((CCDictionary*)obj);
}
else
{
stream << initialStream.str() << typeid(obj).name();
}
return stream.str().c_str();
}
OutputCCObject( obj ) は const char* を返しますので、ケースによってはstring等に保存したりして下さい。
下記の例ではCCLogに出力しているので、そのまま使用しています。
※CCObjectのcreateを使用する際はメモリ管理に気をつけて下さい。
例) これはあくまでも例ですので、実際にCCArrayやCCDictionaryで使う場合はretainを適切にするか、newで作成して下さい。
CCEGLView* view = CCDirector::sharedDirector()->getOpenGLView();
CCSize frameSize = view->getFrameSize();
CCDictionary* paramDic = CCDictionary::create();
paramDic->setObject(CCString::create("ABCD"), "uuid");
paramDic->setObject(CCFloat::create(1.1), "version");
CCArray* mainArray = CCArray::create();
mainArray->addObject(CCBool::create(false));
mainArray->addObject(CCString::create("dummy"));
CCDictionary* arrayDic = CCDictionary::create();
CCArray* subArray = CCArray::create(CCInteger::create(4), CCString::create("test"));
arrayDic->setObject(subArray, "subarray");
mainArray->addObject(arrayDic);
paramDic->setObject(mainArray, "mainarray");
CCDictionary* sizeDic = new CCDictionary();
sizeDic->setObject(CCFloat::create(frameSize.width), "width");
sizeDic->setObject(CCFloat::create(frameSize.height), "height");
sizeDic->setObject(CCBool::create(true), "ios");
paramDic->setObject(sizeDic, "screen");
CCLog("OutputCCObject = %s", OutputCCObject(paramDic));
結果)
OutputCCObject = {"uuid":"ABCD","version":1.1,"mainarray":[false,"dummy",{"subarray":[4,"test",PN7cocos2d8CCObjectE]}],"screen":{"width":640,"height":1136,"ios":true}}
今回は std::ostringstream を使いましたが、他にももっと良い方法があるかと思います。
もし良いアイディアがあったら教えて下さい。
よろしくお願いします。