4

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();
    }
}
Bungles
  • 1,969
  • 2
  • 25
  • 54

2 Answers2

5

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;
}
fireant
  • 14,080
  • 4
  • 39
  • 48
Alex
  • 5,159
  • 4
  • 25
  • 33
  • Modified question to show exact code. All I'm trying to do is get 'metaName' and 'metaValue' as shown. – Bungles May 17 '15 at 21:12
  • 1
    You keep on changing the question but the answer is in the posted code. I have updated it to show exactly how to (1) create json data structure programmatically, (2) serialize it to std::string, (3) parse the std::string back into data structure and (4) traverse the whole structure, detecting nested JSON objects within it. Study the example and you will understand how to do it. – Alex May 17 '15 at 21:22
  • I keep restating the question because you keep not answering it. Your code does not work on my PC so the only other thing I can (and did) do is post my code and have you point out what's wrong. Your code doesn't make any sense to me because it doesn't do what I'm trying to do. – Bungles May 17 '15 at 21:39
  • Then I can't help you, I'm sorry. The code I posted here works and does what you asked for. Good luck with you journey. – Alex May 17 '15 at 21:41
  • So you can't look at the code at the top of this post and see how it's different than what you posted? Your sample code doesn't even compile. – Bungles May 17 '15 at 21:41
  • 1
    No, sorry. I suggest you read the original question that was asked and then study the code I gave you. It works and does what you asked for. – Alex May 17 '15 at 21:45
  • The answer sure does have std::map in it. As to how hard it is to translate from the Object `it->first` and `it->second` to a std:map counterparts I'll leave you to ponder on that. – Alex May 17 '15 at 21:53
  • Really? Sigh. It doesn't EXTRACT to a STD::MAP, which was the entire point of the original and modified question. – Bungles May 17 '15 at 22:15
  • Just out of curiosity, when you ask for a bathroom in a public place, does the person who gives you information also has to help you actually use it? Surely, with a mindset like this, just a direction where the place is won't be enough. But, the attitude has been very educational. I can guarantee you to wait a very long time for another answer from me. – Alex May 17 '15 at 22:23
  • Also, for the record, I've been called a jerk by @Bungles but the comment was later deleted. – Alex May 18 '15 at 00:37
  • Also, for the record, @Alex has been slinging some mud. – Bungles May 18 '15 at 03:18
  • @Alex stands behind everything he posted here, code and otherwise; no deleted comments and no name calling. – Alex May 18 '15 at 03:23
  • So what was that little diddy about going to the restroom? Just because you don't explicitly say something doesn't mean you didn't say it. A personal attack is still a personal attack. I called you a jerk because you were being elitist in the way you answered my question. By deleting it, I was taking that personal attack back not trying to hide it. – Bungles May 18 '15 at 03:30
  • That was a metaphor - I pointed you in the right direction, walked you to the door, opened it for you, but you got upset because I would not go in with you. Since you're not paying me, I can stop helping you at any time and you have no right to be upset. I did help you quite a bit, in my opinion enough to go on your own. It is you who did not do your part - heck even your JSON in the question is not valid. And now I'm done with this. I hope a mod locks this topic cause I'm tired of it. – Alex May 18 '15 at 03:36
  • No, it was a personal attack disguised as a metaphor. What upset me was the tone of your response. You didn't walk me to the door at all. In fact you completely ignored the specificity of my question and then told me it was my fault for not understanding your grand general answer. I posted very specific code that did things a very specify way and you ignored it and told me it was irrelevant. That's not supposed to be upsetting? – Bungles May 18 '15 at 04:14
  • You specifically posted a question about [Poco::JSON::Object](http://stackoverflow.com/revisions/be8e76fc-1f54-4162-ba34-ca3bd943e6a9/view-source), which I have specifically answered with a compilable and functional example showing exactly how to access both top-level and nested JSON objects plus an add-on of DynamicStruct access, which prompted you to latch on to it. At this point, perhaps you would consider accepting the answer and mail me those $500, the promise of which you also deleted? – Alex May 18 '15 at 04:31
  • I have already paid the person who actually answered my question. – Bungles May 18 '15 at 14:22
  • I see, you got the answer and that's why you posted an answer stating that it can't be done? – Alex May 18 '15 at 14:26
  • Many invalid assumptions in that questions, along with a healthy mix of arrogance and condescension. Par for the course. – Bungles May 18 '15 at 19:32
  • Thanks! It seems you meant to write `Var result = parser.parse(os.str());` rather than `Var result = Parser().parse(os.str());` as you've created an object `Parser parser;`. – fireant Oct 16 '15 at 06:57
0

Here's what worked:

// Deserialize from JSON
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 top-level fields
    Poco::DynamicStruct jsonStruct = *parsedResult.extract<Poco::JSON::Object::Ptr>();
    name = jsonStruct["identifier"].toString();

    // Get metadata nested fields
    string keyStr = "metadata";
    Poco::JSON::Object::Ptr jsonObject = parsedResult.extract<Poco::JSON::Object::Ptr>();
    Poco::Dynamic::Var metaVar = jsonObject->get(keyStr);
    Poco::JSON::Object::Ptr metaObj = metaVar.extract<Poco::JSON::Object::Ptr>();
    for (Poco::JSON::Object::ConstIterator itr = metaObj->begin(), end = metaObj->end(); itr != end; ++itr)
        metaData[itr->first] = itr->second.toString();
}

It would appear DynamicStruct cannot be used for nested fields.

Bungles
  • 1,969
  • 2
  • 25
  • 54
  • 1
    Of course it can (and this comment is only to prevent spreading misinformation): `DynamicStruct nestedStruct = jsonStruct["metadata"].extract();` – Alex May 18 '15 at 03:01
  • 1
    See, that wasn't so hard now was it? – Bungles May 18 '15 at 03:16