Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to read json file with optional entries and entries with different types #1281

Closed
dubnde opened this issue Oct 6, 2018 · 2 comments
Closed
Labels
kind: question solution: proposed fix a fix for the issue has been proposed and waits for confirmation

Comments

@dubnde
Copy link

dubnde commented Oct 6, 2018

First of all thansks for this fantastic library. It got me reading dozens of json test files withing minutes.

How do I read from a json file with test vectors in which have optional entries as well as entries that can change the type of the value?

I am wondering how to go about writing the to_json/from_json methods. I particularly I am interested in the from_json to start with. Some of the entries as shown in the example below are optional. For example, the decoded entry as well as the diagnostic entry may or may not appear for each object. Additionally the decoded entry could have values of different types i.e integer, double or string . So I just need to read them out of the file in the best way possible.

    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;

So I have figured out how to do this for the first three entries(cbor, hex, roundtrip) that are always present and don't morph into different types. Could I please have some advice how to handle the other two optional and mutating entries i.e. decoded and diagnostic?

  struct json_test_entry
  {
    std::string cbor;
    std::string hex;
    bool        roundtrip;
    // @TODO Need to add optional/variant "decode/diagnostic" here
  };

  void to_json(nlohmann::json &j, const json_test_entry &p)
  {
    j = json{
      { "cbor", p.cbor }, { "hex", p.hex }, { "roundtrip", p.roundtrip },
      // @TODO Need to add optional/variant "decode/diagnostic" here

    };
  }

  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 >();
    // @TODO Need to decode optional/variant "decode/diagnostic" here
  }

thanks very much as I am sure there is a way of doing this but cannot just see it for now.

the complete file with test vectors is locate here

@dubnde dubnde changed the title Handling to read json file with optional entries and entries with different types How to read json file with optional entries and entries with different types Oct 6, 2018
@nlohmann
Copy link
Owner

nlohmann commented Oct 7, 2018

Here is an example for diagnostic modeled as std::optional<std::string>:

#include "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;
}

The decoded member could be similarly modeled with a std::optional<json> or so.

@nlohmann nlohmann added kind: question solution: proposed fix a fix for the issue has been proposed and waits for confirmation labels Oct 7, 2018
@dubnde
Copy link
Author

dubnde commented Oct 7, 2018

Brilliant. Thank you very much. That does it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind: question solution: proposed fix a fix for the issue has been proposed and waits for confirmation
Projects
None yet
Development

No branches or pull requests

2 participants