nlib
msgpack/json/json.cpp

DOM(MpObject)を用いたJSONの読み書きと、ストリーミングI/Fを用いたJSONの読み書きを行うサンプルです。 前者は以下のようなことを行っています。

後者は以下のようなことを行っています。

一般的にDOMを用いた方が簡単に処理を記述できますが、より多くのメモリを必要とします。 ストリーミングI/Fを用いた場合はその逆です。1つのJSONに対して部分的にDOMを用いて処理を記述することも可能です。
以下がサンプルのソースコードになります。
#include "nn/nlib/msgpack/JsonStreamParser.h"
#include "nn/nlib/msgpack/JsonStreamGenerator.h"
#include "nn/nlib/Nlist.h"
using nlib_ns::msgpack::MpObject;
using nlib_ns::msgpack::JsonStreamParser;
using nlib_ns::msgpack::JsonStreamGenerator;
const char jsontext[] =
"{ \"item\": ["
"{\"itemCode\":91, \"itemName\" : \"ramen with salt based soup\", \"itemPrice\":300},"
"{\"itemCode\":94, \"itemName\" : \"ramen with miso based soup\", \"itemPrice\":290}, "
"{\"itemCode\":95, \"itemName\" : \"ramen with a pork bone broth\", \"itemPrice\":320} "
"] } ";
bool ReadModifyWriteJsonByDom() {
UniquePtr<MpObject> obj;
// Reads the menu data in JSON.
if (JsonStreamParser::Parse(obj, jsontext) != 0) return false;
// You want to raise the prices.
MpObject* price;
int val;
MpObject* items = obj->GetMapItem("item");
if (!items) return false;
MpObject* salt = items->GetArrayItem(0);
if (!salt) return false;
price = salt->GetMapItem("itemPrice");
if (!price) return false;
if (nlib_is_error(price->Unbox(&val))) return false; // Unboxes 'price' and retrieve an integer value.
val += 500; // Changes the price
if (nlib_is_error(price->Box(val))) return false; // Boxes 'val' and updates 'price'.
MpObject* miso = items->GetArrayItem(1);
if (!miso) return false;
price = miso->GetMapItem("itemPrice");
if (!price) return false;
if (nlib_is_error(price->Unbox(&val))) return false;
val += 500;
price->Box(val); // Boxing primitive objects never returns an error.
MpObject* pork = items->GetArrayItem(2);
if (!pork) return false;
price = pork->GetMapItem("itemPrice");
if (!price) return false;
if (nlib_is_error(price->Unbox(&val))) return false;
val += 500;
// You can use the assignment operators instead of boxing
// when you box primitive objects.
*price = val;
// Writes the menu data in JSON.
char str[1024];
if (JsonStreamGenerator::Generate(NULL, str, *obj.get()) != 0) return false;
nlib_printf("%s\n", str);
return true;
}
bool ReadAndWritePriceJsonByStreaming() {
JsonStreamParser parser;
MemoryInputStream istr(jsontext);
if (nlib_is_error(parser.Init())) return false;
if (nlib_is_error(parser.Open(&istr))) return false;
Nlist<int> prices;
JsonStreamParser::Event ev;
if ((ev = parser.Next()) != JsonStreamParser::EVENT_START_MAP) return false;
while ((ev = parser.Next()) != JsonStreamParser::EVENT_END_MAP) {
if (ev != JsonStreamParser::EVENT_KEY_NAME) return false;
if (strcmp(parser.GetToken().buf, "item") == 0) {
if ((ev = parser.Next()) != JsonStreamParser::EVENT_START_ARRAY) return false;
while ((ev = parser.Next()) != JsonStreamParser::EVENT_END_ARRAY) {
if (ev != JsonStreamParser::EVENT_START_MAP) return false;
while ((ev = parser.Next()) != JsonStreamParser::EVENT_END_MAP) {
if (ev != JsonStreamParser::EVENT_KEY_NAME) return false;
if (strcmp(parser.GetToken().buf, "itemPrice") == 0) {
ev = parser.Next();
int num;
if (nlib_is_error(JsonStreamParser::ToInt32(parser.GetToken(), &num)))
return false;
prices.push_back(num);
} else {
if (nlib_is_error(parser.Skip())) return false;
}
}
}
} else {
if (nlib_is_error(parser.Skip())) return false;
}
}
JsonStreamGenerator gen;
char str[1024];
MemoryOutputStream ostr(str);
if (nlib_is_error(gen.Init())) return false;
if (nlib_is_error(gen.Open(&ostr))) return false;
size_t prices_size = prices.size();
gen.StartArray(prices_size);
for (size_t i = 0; i < prices_size; ++i) {
gen.Int32(prices[i]);
}
gen.EndArray();
if (nlib_is_error(gen)) return false;
gen.Close();
if (nlib_is_error(ostr.Write('\0'))) return false;
nlib_printf("%s\n", str);
return true;
}
bool SampleMain(int, char**) {
return ReadModifyWriteJsonByDom() && ReadAndWritePriceJsonByStreaming();
}
NLIB_MAINFUNC