How to parse json file with type composition of std::optional and std::variant

谁都会走 提交于 2020-02-16 12:28:30

问题


How can I parse the input json inside this file, especially for the accuracy, secondary and flags properties?

https://github.com/smogon/pokemon-showdown/blob/master/data/moves.js

They are type composition of optional and variant.

Though only the full example can surface the problem in a clearer way, a minimal starting point example would be this one:

    [
      {},
      {
        "secondary": false
      },
      {

        "secondary": {
          "chance": 10,
          "boosts": {
            "spd": -1
          }
        }
      },
      {
        "secondary": {
          "chance": 30,
          "volatileStatus": "flinch"
        }
      },
      {
        "secondary": {
          "chance": 30
        }
      },
      {
        "secondary": {
          "chance": 10,
          "self": {
            "boosts": {
              "atk": 1,
              "def": 1,
              "spa": 1,
              "spd": 1,
              "spe": 1
            }
          }
        }
      },
      {
        "secondary": {
          "chance": 10,
          "status": "brn"
        }
      },
      {
        "secondary": {
          "chance": 50,
          "self": {
            "boosts": {
              "def": 2
            }
          }
        }
      },
      {
        "secondary": {
          "chance": 100,
          "self": {}
        }
      },
      {
        "secondary": {
          "chance": 50,
          "boosts": {
            "accuracy": -1
          }
        }
      }
    ]

The expected output can be but not limited to:

  1. parsed object which has more structure, such that we can access by key(if it exists)
  2. it has dynamic structure so we can check key existence during run time. For example, "boosts" has only a finite number(<10) of possible keys.

For your convenience, you can attach this snippet to the end of the js file and run it using node move.js. Two valid json files will be saved to your disk. One is a list of json objects while the other is an object with string as key.

var fs = require('fs');
fs.writeFile("moves_object.json", JSON.stringify(BattleMovedex), function(err) {}); // 1. save a json object with string key

var jsonList = []
for (var key of Object.keys(BattleMovedex)) {
    jsonList.push(BattleMovedex[key]);
}
fs.writeFile("moves.json", JSON.stringify(jsonList), function(err) { // 2. save as a list of json object
    if (err) {
        console.log(err);
    }
});

In c++(17/20), there are previous attempts here:
https://github.com/nlohmann/json/issues/1281

https://github.com/nlohmann/json/issues/1910

https://github.com/nlohmann/json/issues/1261

Here is a boiler plate taking care of simple optional fields you can begin with:

#include <nlohmann/json.hpp>
#include <iostream>
#include <iomanip>
#include <optional>

using nlohmann::json;

struct json_test_entry
{
    std::string cbor;
    std::string hex;
    bool        roundtrip;

    std::optional<std::string> diagnostic = std::nullopt;
};

void to_json(nlohmann::json &j, const json_test_entry &p)
{
    j = json{
        { "cbor", p.cbor }, { "hex", p.hex }, { "roundtrip", p.roundtrip }
    };

    // assuming you only want a "diagnostic" key if there is an actual value;
    // if not, store a nullptr and adjust the from_json accordingly
    if (p.diagnostic != std::nullopt)
    {
        j["diagnostic"] = p.diagnostic.value();
    }
}

void from_json(const nlohmann::json &j, json_test_entry &p)
{
    p.cbor      = j.at("cbor").get< std::string >();
    p.hex       = j.at("hex").get< std::string >();
    p.roundtrip = j.at("roundtrip").get< bool >();

    // if we also allow "null" values, then we need to add an "is_string()"
    // check
    if (j.count("diagnostic") != 0)
    {
        p.diagnostic = j.at("diagnostic").get< std::string >();
    }
}
int main()
{
    auto j = R"([
    {
        "cbor" : "GBk=",
        "hex" : "1819",
        "roundtrip" : true,
        "decoded" : 25
    },
    {
        "cbor" : "+T4A",
        "hex" : "f93e00",
        "roundtrip" : true,
        "decoded" : 1.5
    },
    { "cbor" : "YsO8",
        "hex" : "62c3bc",
        "roundtrip" : true,
        "decoded" : "ü"
    },
    { "cbor" : "+X4A",
        "hex" : "f97e00",
        "roundtrip" : true,
        "diagnostic" : "NaN"
    },
    {
        "cbor" : "nwGCAgOfBAX//w==",
        "hex" : "9f018202039f0405ffff",
        "roundtrip" : false,
        "decoded" : [ 1, [ 2, 3 ], [ 4, 5 ] ]
    },
    {
        "cbor" : "gmFhv2FiYWP/",
        "hex" : "826161bf61626163ff",
        "roundtrip" : false,
        "decoded" : [ "a", { "b" : "c" } ]
    }
    ])"_json;

    // roundtrip and preserves "diagnostic" entries
    std::vector<json_test_entry> v = j;
    json k = v;
    std::cout << std::setw(2) << k << std::endl;
}

来源:https://stackoverflow.com/questions/59919496/how-to-parse-json-file-with-type-composition-of-stdoptional-and-stdvariant

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!