

VisualStudio2012 C++に [picojson](https://github.com/kazuho/picojson) を組み込んで
json ファイルを読みこませようとしたのですが、jsonファイルの階層構造に対応した読込がうまくいかず躓いてしまっています。  
（一番欲しいデータは、jsonファイルにある"paths"のarrayにある複数の2次元配列です）

単純な1階層目ではビルドも通り、実行しても読みこまれているようなのですが、  
途中array構造の中のパラメータを読みこませるところから、うまくいかない状態です。

### 該当のソースコード

**読み込むためのソースコード**

[code]

      // ファイルを読み込むための変数
      std::ifstream fs;
    
      // ファイルを読み込む
      fs.open("sample.json", std::ios::binary);
    
      // 読み込みチェック
      // fs変数にデータがなければエラー
      assert(fs);
    
      // Picojsonへ読み込む
      picojson::value val;
      fs >> val;
    
      // fs変数はもう使わないので閉鎖
      fs.close();
    
      // Playerの名前を取得
        picojson::object& obj = val.get<picojson::object>();
        picojson::array& feat = obj["features"].get<picojson::array>();     // ★ここまでは読みこめる
    
[/code]

**読みこませたいjsonファイル (sample.json)**

[code]

    {
      "displayFieldName": "",
      "geoType": "geotype01",
      "features": [
        {
          "attributes": {
            "FID": 0,
            "prop0": "123456"
          },
          "param": {
            "paths": [
              [
                [
                  100.123,
                  23.456
                ],
                [
                  123.456,
                  34.567
                ],
                [
                  135.790,
                  45.678
                ],
                [
                  111.222,
                  56.789
                ]
              ]
            ]
          }
        },
        {
          "attributes": {
            "FID": 1,
            "prop0": "124816"
          },
          "param": {
            "paths": [
              [
                [
                  123.456,
                  98.876
                ],
                [
                  234.567,
                  87.654
                ],
                [
                  345.678,
                  76.543
                ],
                [
                  456.789,
                  65.432
                ]
              ]
            ]
          }
        },
      ],
      "fieldAliases": {
        "FID": "FID",
        "prop0": "prop0"
      },
      "fields": [
        {
          "alias": "FID",
          "name": "FID",
          "type": "FieldTypeAAA"
        },
        {
          "alias": "prop0",
          "length": 254,
          "name": "prop0",
          "type": "FieldTypeString"
        }
      ],
      "spatialReference": {
        "latestWkid": 4321,
        "wkid": 4321
      }
    }
    
[/code]

のように階層が何層にも続いているので、それを読ませる方法がわからなくて困っています。  
（picojsonの紹介サイトは多いのですが、sampleのような階層構造になっているものに対しての記述が載っているサイトが見当たらなくて困っています）

### 試したこと

"feature"のタグのついたarrayが複数（ここでは2つ）あるので、それを以下の記述で読ませました。

[code]

    picojson::array& feat = obj["features"].get<picojson::array>();
    
[/code]

ただ、そのあと、arrayの中にある各種タグのついたデータの読み込み方がわからず詰まってしまっています。

[code]

    // featuresの数ぶんまわす
    for (int i = 0; i < feat.size(); i++){
      // attributes
      string hoge = obj["attributes"].get<string>();
    、、、
    
[/code]

のように、"features"のarrayのかずだけループで読ませるのかと思ったのですがダメでした。

* * *

**補足情報（FW/ツールのバージョンなど）**

先にも書きましたが、  
・sample.jsonのような階層構造になっている場合の読み込みのための記述方法を教えていただきたいです。  
・一番欲しいデータは"paths"のarrayにある複数の2次元配列で、vector型で格納したいと考えています。  
・今回はpicojsonで試していますが、他でも結構ですのでもし良いものがあれば是非教えていただけると嬉しいです。

もしお分かりの方がいらっしゃいましたら、記述する際のコツやノウハウについて教えていただけると大変助かります。  
是非ご教授いただけますようよろしくお願いいたします。


CC BY-SA 4.0
2020-07-01T23:42:08.343
68200
2020-07-17T17:24:21.953
2020-07-17T17:24:21.953
3060
40898
question
c++ json array データ構造
階層構造を含む JSON ファイルを読ませたい


回答の前に、直接は関係無いですが [JSON Pretty Linter Ver3](https://lab.syncer.jp/Tool/JSON-
Viewer/)とか[Best JSON Formatter and JSON Validator: Online JSON
Validator](https://jsonformatter.org/)に掛けると`Parse error on line
60:`と出てくるのですが、その行の`},`のカンマを削除して`}`だけにしたらチェックは通ったようです。

JSONの中身がオブジェクトや配列になっているので、以下のように地道に構造に従って段階的に内部にアクセスする必要があるでしょう。  
もっと上手にやる方法(配列はインデックスでは無く別の方法で回すとか)はあるでしょうが、とりあえずはこんな感じで出来ます。

**以下を修正：**  
「一番欲しいデータは"paths"のarrayにある複数の2次元配列で、vector型で格納したい」への対応としては以下のようなクラスを定義しておきます。「複数の2次元配列」はその通り3次元配列として格納します。

[code]

    class feature {
    public:
        double FID;
        std::string prop0;
        std::vector<std::vector<std::vector<double>>> paths;
    };
    
[/code]

「// ★ここまでは読みこめる」の後に以下の処理を入れます。出力処理は確認用です。

[code]

    std::vector<feature> features(feat.size());
    
    // featuresの数ぶんまわす
    for (unsigned int i = 0; i < feat.size(); i++) {
        // attributes
        //string hoge = obj["attributes"].get<string>();
        picojson::object& featN = feat[i].get<picojson::object>();
        picojson::object& attr = featN["attributes"].get<picojson::object>();
    
        features[i].FID = attr["FID"].get<double>();
        features[i].prop0 = attr["prop0"].get<std::string>();
    
        std::cout << "features: " << i << ",  FID: " << features[i].FID << ",  prop0: " << features[i].prop0 << std::endl;
    
        picojson::object& param = featN["param"].get<picojson::object>();
        picojson::array& paths = param["paths"].get<picojson::array>();
    
        features[i].paths.resize(paths.size());  // サンプルでは1のみ
        for (unsigned int j = 0; j < paths.size(); j++) {
    
            picojson::array& pathD2 = paths[j].get<picojson::array>();
            features[i].paths[j].resize(pathD2.size());  // サンプルでは4のみ
            for (unsigned int k = 0; k < pathD2.size(); k++) {
    
                picojson::array& pathD3 = pathD2[k].get<picojson::array>();
                features[i].paths[j][k].resize(pathD3.size()); // サンプルでは2のみ
                for (unsigned int l = 0; l < pathD3.size(); l++) {
                    features[i].paths[j][k][l] = pathD3[l].get<double>();
                    std::cout << "    paths 1stIdx: " << j << ",  2ndIdx: " << k << ",  3rdIdx: " << l << ", value: " << features[i].paths[j][k][l] << std::endl;
                }
            }
        }
    }
    
[/code]


CC BY-SA 4.0
2020-07-02T02:26:44.980
68204
2020-07-02T16:49:16.657
2020-07-02T16:49:16.657
26370
26370
68200
answer