Home > Back-end >  Inconsistent IsObject() property in searching through nested properties in rapidjson document
Inconsistent IsObject() property in searching through nested properties in rapidjson document

Time:09-22

I'm having an issue where the rapidjson library appears to be inconsistent as to when it reports IsObject() as true.

Sometimes when I call value.IsObject() after retrieving a Value from a Document, it correctly reports it as an Object. But sometimes it reports what I think should be an Object as not an Object.

A toy program is below.

It seems I am unintentionally mutating the document somehow, as the 2nd lookup for vegetables::celery remarkably fails.

#define _CRT_SECURE_NO_DEPRECATE

#include <rapidjson/document.h>
#include <rapidjson/writer.h>
#include <rapidjson/stringbuffer.h>
#include <string.h>
#include <stdio.h>
using namespace rapidjson;

int getInt(Document& jsonDoc, const char* propertyName)
{
    if (!jsonDoc.IsObject()) {
        puts("Err: jsonDoc not an object");
        return 0;
    }

    char* str = strdup(propertyName);
    char* p = strtok(str, ":");
    printf("Looking for property `%s`\n", p);
    if (!jsonDoc.HasMember(p))
    {
        printf("  - Error: %s not found, property %s\n", p, propertyName);
        free(str);
        return 0;
    }
    else
    {
        printf("  - found property '%s'\n", p);
    }

    rapidjson::Value& v = jsonDoc[p];
    
    while (p = strtok(0, ":"))
    {
        printf("Looking for property `%s`\n", p);
        if (v.IsObject())
        {
            puts("  - v is an object so I can look");
        }
        else
        {
            printf("  - ERROR: v is NOT an object, I can't search for %s, property %s not found\n", p, propertyName);
            free(str);
            return 0;
        }

        if (!v.HasMember(p))
        {
            printf("  - Error while digging: %s not found, property %s\n", p, propertyName);
            free(str);
            return 0;
        }
        else
            printf("  - found property '%s'\n", p);

        // otherwise,
        v = v[p];  // advance deeper into the tree
    }

    int val = v.GetInt();
    printf("  - json got value %s=%d\n", propertyName, val);
    free(str);
    return val;
}

void test1()
{
    const char* json = R"STR({
      "fruits":{
        "apples":1,
        "oranges":553,
        "bananas":900
      },
      "vegetables":{
        "celery":10000,
        "cabbage":10000
      }
    })STR";

    Document d;
    d.Parse(json);

    int apples = getInt(d, "fruits::apples");
    int oranges = getInt(d, "fruits::oranges");
    int bananas = getInt(d, "fruits::bananas");

    int celery = getInt(d, "vegetables::celery");
    celery = getInt(d, "vegetables::celery");
    int cabbage = getInt(d, "vegetables::cabbage");
}

int main()
{
    test1();
    return 0;
}

CodePudding user response:

Two issues here.

First and main:

 rapidjson::Value& v = jsonDoc[p];
 ...
 v = v[p];  

Since v is not a variable, but a reference, you don't set it to a new object, but change the original object it references to, damaging it.

Use rapidjson library Pointers if you need to change the object beneath or you can use a trick like here:

 rapidjson::Value* v = &(jsonDoc[p]);
 ...
 v = &(*v)[p]; 

Second

In some returns in if-else you have the memory leak with str, you free it only at the end of the function.

  • Related