c++jsonboostboost-propertytree

Read a sub json using boost property tree


I need to read a field in a JSON file which itself is a JSON. I need to read the JSON field in one go. Is there any way available? Sample JSON I am trying to read is provided below.

enter code here
   {
      "responses": [
       { 
          "id": "1",
          "status": 200,
          "headers": {
                 "OData-Version": "4.0",
                 "Content-Type":"application/json;odata.metadata=minimal;odata.streaming=true"
           },
          "body": {        
              "createdDateTime": "2021-04-22T09:24:59.394Z",
              "displayName": "Test1",        
              "visibility": "public",        
              "isMembershipLimitedToOwners": false,
              "discoverySettings": { "showInTeamsSearchAndSuggestions": true },
              "memberSettings": {
              "allowCreateUpdateChannels": true,
              "allowCreateUpdateRemoveConnectors": true
           },
           "guestSettings": {
              "allowCreateUpdateChannels": true,
              "allowDeleteChannels": false
            },
            "messagingSettings": {
              "allowUserEditMessages": true,
              "allowChannelMentions": true
            },
            "funSettings": {
              "allowGiphy": true,
              "allowCustomMemes": true
            }
          }    }  ]
        }

I am trying to read the "body" field using the code below (json is read in boost::property_tree::ptree jsonBatchResponse jsonBatchResponse). But strBody is empty and it doesn't read the "Body" field correctly. :

enter code here
     for (auto& v : jsonBatchResponse.get_child("responses"))
     {       
        std::string strID = v.second.get<std::string>("id", "");
        std::string strStatus = v.second.get<std::string>("status", "");
        std::string strBody = v.second.get<std::string>("body", "");
     }

It looks like v.second.getstd::string("body", "") is not the right way to read the JSON field. Is there any other way available (other than reading individual fields in the JSON value)? Please let me know.


Solution

  • The body is not a string.

    So, getting the child object would be in order:

    for (auto const& v : jsonBatchResponse.get_child("responses")) {
        std::string  strID     = v.second.get<std::string>("id", "");
        std::string  strStatus = v.second.get<std::string>("status", "");
        ptree const& body      = v.second.get_child("body");
    }
    

    If you add some output to that loop with e.g.

        std::cout << std::quoted(strID) << "\n";
        std::cout << std::quoted(strStatus) << "\n";
        write_json(std::cout, body);
    

    It will print Live On Coliru

    "1"
    "200"
    {
        "createdDateTime": "2021-04-22T09:24:59.394Z",
        "displayName": "Test1",
        "visibility": "public",
        "isMembershipLimitedToOwners": "false",
        "discoverySettings": {
            "showInTeamsSearchAndSuggestions": "true"
        },
        "memberSettings": {
            "allowCreateUpdateChannels": "true",
            "allowCreateUpdateRemoveConnectors": "true"
        },
        "guestSettings": {
            "allowCreateUpdateChannels": "true",
            "allowDeleteChannels": "false"
        },
        "messagingSettings": {
            "allowUserEditMessages": "true",
            "allowChannelMentions": "true"
        },
        "funSettings": {
            "allowGiphy": "true",
            "allowCustomMemes": "true"
        }
    }
    

    BONUS: Using a proper JSON library instead

    Boost Property Tree is NOT a JSON library, and therefore has a lot of limitations.

    Instead I suggest using Boost JSON:

    Live On Coliru

    #include <boost/json.hpp>
    #include <boost/json/src.hpp>
    #include <iostream>
    
    namespace json = boost::json;
    
    extern std::string sample;
    
    int main() {
        json::object jsonBatchResponse = json::parse(sample).as_object();
    
        for (auto& v : jsonBatchResponse["responses"].as_array()) {
            auto& res = v.as_object();
            json::value id  = res["id"],     // string
                status      = res["status"], // integer
                body        = res["body"];   // object
            std::cout << id << "\n";
            std::cout << status << "\n";
            std::cout << body << "\n";
        }
    }
    
    std::string sample = R"(
    {
        "responses": [{
            "id": "1",
            "status": 200,
            "headers": {
                "OData-Version": "4.0",
                "Content-Type": "application/json;odata.metadata=minimal;odata.streaming=true"
            },
            "body": {
                "createdDateTime": "2021-04-22T09:24:59.394Z",
                "displayName": "Test1",
                "visibility": "public",
                "isMembershipLimitedToOwners": false,
                "discoverySettings": {
                    "showInTeamsSearchAndSuggestions": true
                },
                "memberSettings": {
                    "allowCreateUpdateChannels": true,
                    "allowCreateUpdateRemoveConnectors": true
                },
                "guestSettings": {
                    "allowCreateUpdateChannels": true,
                    "allowDeleteChannels": false
                },
                "messagingSettings": {
                    "allowUserEditMessages": true,
                    "allowChannelMentions": true
                },
                "funSettings": {
                    "allowGiphy": true,
                    "allowCustomMemes": true
                }
            }
        }]
    }
    )";
    

    Prints

    "1"
    200
    {"createdDateTime":"2021-04-22T09:24:59.394Z","displayName":"Test1","visibility":"public","isMembershipLimitedToOwners":false,"discoverySettings":{"showInTeamsSearchAndSuggestions":true},"memberSettings":{"allowCreateUpdateChannels":true,"allowCreateUpdateRemoveConnectors":true},"guestSettings":{"allowCreateUpdateChannels":true,"allowDeleteChannels":false},"messagingSettings":{"allowUserEditMessages":true,"allowChannelMentions":true},"funSettings":{"allowGiphy":true,"allowCustomMemes":true}}