C++
JSON
構文解析
picojson

C++のJSONパーサ『picojson』をためしてみました。

はじめに

C++やJSONを扱うことが多いのですが、とうとうC++でJSONをパースする必要に迫られそうなので
予習がてらに有名なC++のJSONパーサのひとつであるpicojsonをためしてみました。

なぜ最初にpicojsonをためしてみたか

C++のJSONパーサで聞いたことあるライブラリといえばpicojsonとrapidjson、それにboost::property_treeだったのですが、
調べたところ

  1. picojsonが一番簡単そう
  2. 今回は速度を重視しない
  3. boost::property_treeは木構造を汎用的に扱う管理ライブラリであり、XMLやJSONに対して統一的なアクセス方法を提供するためのもの

の3点からpicojsonがいいかなと思いました。
他2つもよさそうですが触るのは次の機会にします。

コードはこんな感じ

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <iterator>
#include "picojson.h"

int main(void)
{
    // JSONデータの読み込み。
    std::ifstream ifs("test.json", std::ios::in);
    if (ifs.fail()) {
        std::cerr << "failed to read test.json" << std::endl;
        return 1;
    }
    const std::string json((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
    ifs.close();

    // JSONデータを解析する。
    picojson::value v;
    const std::string err = picojson::parse(v, json);
    if (err.empty() == false) {
        std::cerr << err << std::endl;
        return 2;
    }

    std::cout << "いったんすべてを出力してみる。" << std::endl;
    std::cout << v << std::endl;
    std::cout << std::endl;

    std::cout << "パースされたデータをのぞいてみる。" << std::endl;
    picojson::object& obj = v.get<picojson::object>();
    std::cout << "string: "                         << obj["string"].get<std::string>()       << std::endl;
    std::cout << "number_double: "                  << obj["number_double"].get<double>()     << std::endl;
    std::cout << "number_integer: "                 << obj["number_integer"].get<double>()    << std::endl;
    std::cout << "boolean_true: " << std::boolalpha << obj["boolean_true"].get<bool>()        << std::endl;
    std::cout << "boolean_false: "<< std::boolalpha << obj["boolean_false"].get<bool>()       << std::endl; 
    std::cout << "array: ";
    picojson::array& ary = obj["array"].get<picojson::array>();
    for (const auto& e : ary) {  // vectorをrange-based-forでまわしている。
        std::cout << e.get<std::string>() << " ";
    }
    std::cout << "\n\n";

    std::cout << "ループをまわしてみる。" << std::endl;
    for (const auto& p : obj) { // mapをrange-based-forでまわしている。
        std::cout << p.first << ": " << p.second.to_str() << std::endl;
    }

    return 0;
}
入力(test.json)
{
    "string": "テスト0",
    "number_double": 123.456,
    "number_integer": 123456,
    "boolean_true": true,
    "boolean_false": false,
    "array": [
         "array_elem0",
         "array_elem1",
         "array_elem2"
    ]
}
出力結果
いったんすべてを出力してみる。
{"array":["array_elem0","array_elem1","array_elem2"],"boolean_false":false,"boolean_true":true,"number_double":123.456,"number_integer":123456,"string":"テスト0"}

パースされたデータをのぞいてみる。
string: テスト0
number_double: 123.456
number_integer: 123456
boolean_true: true
boolean_false: false
array: array_elem0 array_elem1 array_elem2

ループをまわしてみる。
array: array
boolean_false: false
boolean_true: true
number_double: 123.456
number_integer: 123456
string: テスト0

感想

STLフレンドリーをうたうだけあってとっかかりやすかったです。
実務では最後のループを再帰的に展開する感じになるのかな?

JSONではintやdoubleという分類はなく、どちらもnumberとなるのでget<double>()で取得できるようです。

参考

https://github.com/kazuho/picojson
https://qiita.com/voluntas/items/48ec1b9dc781a1571545
https://www.mk-mode.com/octopress/2014/11/15/cpp-parse-json-by-picojson/

Why do not you register as a user and use Qiita more conveniently?
You seem to be reading articles frequently this month. You can use this function by logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away