How to create and parse hierarchical/nested JSON with Poco C++?

Bungles picture Bungles · May 15, 2015 · Viewed 7.8k times · Source

Edited to simplify and show my EXACT code.

I have the following data that I need to serialize to JSON as well as parse from JSON.

string name;
std::map<string, string> metaData;

I need the JSON to be nested/hierarchical like this:

{
    "name":"john smith"
    "metadata":
    {
        "age":45,
        "middle_name":"william",
    },
}

Here is my EXACT code:

void DeserializeFromJSON(string &jsonString)
{
    // Parse the JSON
    Poco::JSON::Parser jsonParser;
    Poco::Dynamic::Var parsedJSON = jsonParser.parse(jsonString);
    Poco::Dynamic::Var parsedResult = jsonParser.result();

    // Extract the JSON Object
    Poco::DynamicStruct jsonStruct = *parsedResult.extract<Poco::JSON::Object::Ptr>();

    // Get the name
    name = jsonStruct["name"].toString();

    // Get the meta data -- which of these should I use???
    Poco::Dynamic::Var metaVar = jsonStruct["metadata"];
    Poco::JSON::Object metaObj = jsonStruct["metadata"];

    // At this point, exactly what is it I have in 'metaVar' and 'metaObj'?

    // If I try to loop like you say, I get compiler error C2664 in "var.h"
    for (Poco::JSON::Object::ConstIterator itr = jsonObject.begin(), end = jsonObject.end(); itr != end; ++itr)
    {
        string metaName = itr->first;
        string metaValue = itr->second.toString();
    }
}

Answer

Alex picture Alex · May 15, 2015

UPDATE: while putting together this example, I found a subtle bug; it is fixed in the repo for upcoming 1.6.1 and 1.7.0 release. The sample below works fine with earlier releases, just don't use preserve order with JSON::Stringifier::stringify() (using Object::stringify() is fine).

Here you go; if you don't care about preserving JSON entries insertion order, don't pass anything to Object constructor - it will perform slightly better:

#include "Poco/JSON/Parser.h"
#include "Poco/JSON/ParseHandler.h"
#include "Poco/JSON/Stringifier.h"

using Poco::JSON::ParseHandler;
using Poco::JSON::Stringifier;
using Poco::JSON::Object;
using Poco::JSON::Parser;
using Poco::Dynamic::Var;
using Poco::DynamicStruct;

void objPrint(Object& obj, const std::string& name = "")
{
    for (Object::ConstIterator it = obj.begin(),
        end = obj.end(); it != end; ++it)
    {
        if (!name.empty()) std::cout << name << ':';
        std::cout << it->first << ':';
        if (it->second.type() == typeid(Object::Ptr))
        {
            Object::Ptr p = it->second.extract<Object::Ptr>();
            objPrint(*p, it->first);
        }
        else
             std::cout << it->second.toString() << std::endl;
    }
}

int main(int, char**)
{
    typedef std::map<std::string, int> PersonMap;

    std::string timeStamp = "2015-05-14T17:47:21.999Z";
    Poco::Int32 identifier = 3;
    std::string name = "john smith";
    PersonMap metaData;
    metaData.insert(PersonMap::value_type("william", 45));

    Object obj(true);
    obj.set("ts", timeStamp);
    obj.set("name", name);
    obj.set("identifier", identifier);
    Object::Ptr pMD = new Poco::JSON::Object(true);
    for (PersonMap::iterator it = metaData.begin(),
        end = metaData.end(); it != end; ++it)
    {
        pMD->set("middle_name", it->first);
        pMD->set("age", it->second);
    }
    obj.set("metadata", pMD);

    std::ostringstream os;
    obj.stringify(os, 2);
    std::cout << os.str() << std::endl;

    Parser parser;
    Var result = parser.parse(os.str());

    Object::Ptr pObj = result.extract<Object::Ptr>();
    objPrint(*pObj);

    return 0;
}