手前味噌ですが, 最近ofxJsonUtilsというaddonを書いてまして, それの紹介.
ofxJsonUtilsとは
今後ofxXmlSettingが無くなってofXmlになりそうなのですがこれがまた非常に使いづらい.
そもそもXMLの閉じタグが嫌いだしjs大好き勢としてはjson最高って言いたい.
でもofのaddonでjsonの決定打がなかなか出ないのですが, 多分0.10.0からnlohmann/jsonというC++11なモダンなjsonライブラリがusing ofJson = nlohmann::json; として使えるようになります.
で, それを先取りしてofxJsonUtilsというのを書いてまして, nlohmann::jsonが無い場合はofJsonとして読み込んでしまったりとかして今後も互換性を保てるjson使いが出来る, と.
そんで, nlohmann::json はなかなかイケてるんですが痒いところに手が届かないのでラッパーライブラリ的なのも書いている状況です.
ofxJsonUtils::loadFromFile
毎回ファイルからテキスト読み込んでパースしてっていう数行のことですが, 大体定型文なので関数にしてます.
ofJson json = ofxJsonUtils::loadFromFile("hoge.json");
toJson, loadJson
例えば,
struct my_struct {
ofVec3f point;
int radius;
};
のようなクラス/構造体をjsonにシリアライズしたい場合に
struct my_struct {
ofVec3f point;
int radius;
ofJson toJson() const {
ofJson json;
json["point"] = ofxJsonUtils::convert(point);
json["raidus"] = radius;
return json;
}
void loadJson(const ofJson &json) {
ofxJsonUtils::parse(json["point"], point);
ofxJsonUtils::parse(json["radius"], radius);
}
};
と toJson
, loadJson
を定義しておくと今度は
struct other_struct {
std::vector<my_struct> objs;
ofJson toJson() const {
ofJson json;
json["objs"] = ofxJsonUtils::convert(objs);
return json;
};
void loadJson(const ofJson &json) {
ofxJsonUtils::parse(json["objs"], objs);
}
};
と再帰的に使っていくことが出来ます.
既に存在する自分が手を入れれないクラスに関しても
struct not_my_struct { ... };
ofJson convert(const not_my_struct &value) {
return {
{"x", value.x},
{"y", value.y}
};
}
void parse(const ofJson &json, not_my_struct &value) {
value.x = json["x"];
value.y = json["y"];
}
と関数を定義することで外部からでも対応させることが出来ます.
ofxJsonify
また, ofxJsonify
というtemplateクラスを使うと
struct other_struct : public ofxJsonify<other_struct> {
std::vector<my_struct> objs;
ofJson toJson() const {
ofJson json;
json["objs"] = ofxJsonUtils::convert(objs);
return json;
};
void loadJson(const ofJson &json) {
ofxJsonUtils::parse(json["objs"], objs);
}
}
とするだけで
other_struct s;
s.loadFromJsonFile("hoge.json");
s.loadFromJsonString("{\"objs\":[]}");
s.writeToJsonFile("bar.json");
std::string str = s.toJsonString();
ofJson json = s;
といったファイルへの書き込み/読み込み, 文字列の書き出し/読み込み, オペレーターオーバーロードを裏で実装してくれます.
create
, load
最初の例の
struct my_struct {
ofVec3f point;
int radius;
ofJson toJson() const {
ofJson json;
json["point"] = ofxJsonUtils::convert(point);
json["raidus"] = radius;
return json;
}
void loadJson(const ofJson &json) {
ofxJsonUtils::parse(json["point"], point);
ofxJsonUtils::parse(json["radius"], radius);
}
};
は, create
/ load
を使うと次のようにも書けます.
struct my_struct {
ofVec3f point;
int radius;
ofJson toJson() const {
return ofxJsonUtils::create("point", point, "radius", radius);
}
void loadJson(const ofJson &json) {
ofxJsonUtils::load(json, "point", point, "radius", radius);
}
};
更に, kv
マクロを使うと
struct my_struct {
ofVec3f point;
int radius;
ofJson toJson() const {
return ofxJsonUtils::create(kv(point), kv(radius));
}
void loadJson(const ofJson &json) {
ofxJsonUtils ::load(json, kv(point), kv(radius));
}
};
と書けます.
oFクラスの対応状況
現状は
-
ofVec2f
:{"x": 0.0, "y": 0.0}
-
ofVec3f
:{"x": 0.0, "y": 0.0, "z": 0.0}
-
ofVec4f
:{"x": 0.0, "y": 0.0, "z": 0.0, "w": 0.0}
-
ofRectangle
:{"x": 0.0, "y": 0.0, "width": 0.0, "height": 0.0}
-
ofMatrix4x4
:{"value0": (ofVec4f), "value1": (ofVec4f), "value2": (ofVec4f), "value3": (ofVec4f)}
-
ofColor_<Type>
:{"r": (Type), "g": (Type), "b": (Type), "a": (Type)}
-
std::vector<Type>
,std::deque<Type>
,std::array<Type>
:[(Type) ...]
-
std::map<std::string, Type>
:{key: (Type)}
といった感じで対応しています.
最後に
まだ書き始めたばかりなので欲しい機能があった場合はissue立ててもらえると有難いです.
もちろん, 機能追加やバグフィクスのPRもお待ちしております.
以上, 宣伝でした.