Poco C++ building nested JSON objects
Asked Answered
F

2

9

I have a nested JSON object. I'm trying to build it in a function and add the inner object to the original, but I can't extract the result.

void build_object (Poco::JSON::Object * const result)
{

    /* Construct some int/bool/string fields here */

    Poco::JSON::Object inner;
    inner.set("some_number", 5);
    inner.set("some_string", "xyz");

    /* This is where it breaks down */ 
    std::string key = "new_object";
    result->set("new_object", inner);

    /* Then some debugging and testing */
    // The new object is printed inside the first -> seems like it's working
    result->stringify(std::cout); 

    printf("result has(key): %i\n", result->has(key)); // true
    printf("isObject: %i\n", result->isObject(key));   // false - huh?
    printf("isNull: %i\n", result->isNull(key));       // false
    printf("isArray: %i\n", result->isArray(key));     // false

    Poco::JSON::Object::Ptr ptr = result->getObject(key); 
    // unsurpisingly fails since the above indicates it's not an object
    printf("ptr isNull: %i\n", ptr.isNull());          // true
    // ptr->has("some_number"); // throws NullPointerException

    // if it's not an object/null/array, it must be a value
    Poco::Dynamic::Var v = result->get(key);
    // at least one of these things should be true, otherwise what is it?
    printf("var isString: %i\n", v.isString());  // false
    printf("var isStuct: %i\n", v.isStruct());   // false
    printf("var isEmpty: %i\n", v.isEmpty());    // false
    printf("var isArray: %i\n", v.isArray());    // false
    printf("var isSigned: %i\n", v.isSigned());  // false
    printf("var isNumeric: %i\n", v.isNumeric());// false
}

So, I have an inner object that is correctly put into the result, it is being printed via stringify with all the correct values and result->has() is successful. But, according to the result, it is not an object, array, or null, so you should be able to get it with var. But, once it's gotten from var, it's not a string, struct, array, or number, and it's also not empty. The inner object seems to exist and not exist at the same time.

So, how do I put this object into my result? And how do I get it out?

Thanks

note: I've seen this thread Correct usage of Poco C++ JSON for parsing data, but it's building the JSON object from string and then parsing it. I suppose I could build everything as a string and convert to the Poco Object at the last step, but I'm still curious why the above is happening. Also, using result->set() and result->get() are a cleaner, less hack-y solution than going through a string.

References: Poco JSON Doc, Poco Dynamic Var Doc

Frasquito answered 7/3, 2015 at 16:52 Comment(2)
What is the return type for result->has result->isObject, etc.? If it's bool, then it is undefined behavior to use bool in a printf() statement as there is no official format specifier for bool.Casseycassi
return type is bool. I'm substituting true and false for 1 and 0 in my comments above. It's not a printing issue - I can cast them all to int and get the same result, also as a more conclusive null object test, attempting to use the ptr from ptr=result->getObject(key) throws a null pointer exceptionFrasquito
A
11

Poco::JSON Objects and Arrays are held as shared pointers internally by default (optimization to avoid values copying) and everything is Dynamic::Var, so it works for both pointers and values. When you insert an Object as value it works because Dynamic::Var will hold pretty much anything, but the problem you experience when inspecting it comes from the fact that internal comparison does not return true for Object values because it compares only with default type - Poco::SharedPtr<Poco::JSON::Object>.

Here's a workaround:

void build_object (Poco::JSON::Object * const result)
{
    // smart pointer, so don't worry about cleaning up
    Poco::JSON::Object::Ptr inner = new Poco::JSON::Object;
    inner->set("some_number", 5);
    inner->set("some_string", "xyz");

    std::string key = "new_object";
    result->set(key, inner);
    printf("isObject: %i\n", result->isObject(key)); // true
}

I have opened a github issue to alleviate this caveat.

Annates answered 8/3, 2015 at 4:50 Comment(0)
P
2

I have been trying to create json file having nested object using poco library. Finally able to do with Poco::Json::Array.

Please find the posted code sinippet. Hope it will help. Json output attached with post.

#include "Poco\JSON\JSON.h"
#include "Poco\JSON\Stringifier.h"
#include "Poco\JSON\Object.h"
#include "Poco\Dynamic\Var.h"


using namespace std;
using Poco::JSON::Stringifier;
using Poco::JSON::Object;
using Poco::JSON::Array;

        void makeJsonNestedObject()
    {
        Object RootObj(true);
        Array FLArray;

        for(int i=0; i<3; i++)
        {       
            Object::Ptr FirstLevelArrayNode = new Poco::JSON::Object(true);
            TCHAR strNameBuff[15];
            _stprintf(strNameBuff, _T("%s_%d"),_T("Servername"),i);
            std::basic_string<TCHAR> strName = strNameBuff;


            FirstLevelArrayNode->set("HostName", strName);
            FirstLevelArrayNode->set("Overall Impact", "Dummy Data");

            Array SLArray;

            for(int j=0; j<3;j++)
            {
                Object::Ptr SecondLevelArrayNode = new Poco::JSON::Object(true);
                TCHAR attr1NameBuff[15];
                TCHAR attr2NameBuff[15];
                _stprintf(attr1NameBuff, _T("%s_%d"),_T("AttrOne"),j);
                _stprintf(attr2NameBuff, _T("%s_%d"),_T("AttrTwo"),j);
                std::basic_string<TCHAR> attr1Name = attr1NameBuff;
                std::basic_string<TCHAR> attr2Name = attr2NameBuff;
                SecondLevelArrayNode->set("Attribute", attr1Name);
                SecondLevelArrayNode->set("SubAttribute", attr2Name);
                Poco::Dynamic::Var obj(SecondLevelArrayNode);
                SLArray.add(obj);
            }   
            FirstLevelArrayNode->set("Attribute_Details",SLArray);
            Poco::Dynamic::Var FLArrayNodeobj(FirstLevelArrayNode);
            FLArray.add(FLArrayNodeobj);

        }
        std::ostringstream os;
        std::cout <<"before stringlify.." << std::endl;
        FLArray.stringify(os, 2);
        std::cout << os.str() << std::endl;

    }

Json output:

    [
  {
    "HostName" : "Servername_0",
    "Overall Impact" : "Dummy Data",
    "Attribute_Details" : [
      {
        "Attribute" : "AttrOne_0",
        "SubAttribute" : "AttrTwo_0"
      },
      {
        "Attribute" : "AttrOne_1",
        "SubAttribute" : "AttrTwo_1"
      },
      {
        "Attribute" : "AttrOne_2",
        "SubAttribute" : "AttrTwo_2"
      }
    ]
  },
  {
    "HostName" : "Servername_1",
    "Overall Impact" : "Dummy Data",
    "Attribute_Details" : [
      {
        "Attribute" : "AttrOne_0",
        "SubAttribute" : "AttrTwo_0"
      },
      {
        "Attribute" : "AttrOne_1",
        "SubAttribute" : "AttrTwo_1"
      },
      {
        "Attribute" : "AttrOne_2",
        "SubAttribute" : "AttrTwo_2"
      }
    ]
  },
  {
    "HostName" : "Servername_2",
    "Overall Impact" : "Dummy Data",
    "Attribute_Details" : [
      {
        "Attribute" : "AttrOne_0",
        "SubAttribute" : "AttrTwo_0"
      },
      {
        "Attribute" : "AttrOne_1",
        "SubAttribute" : "AttrTwo_1"
      },
      {
        "Attribute" : "AttrOne_2",
        "SubAttribute" : "AttrTwo_2"
      }
    ]
  }
]
Parrott answered 1/9, 2015 at 9:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.