Search code examples
c++c++17jsoncpp

Is there a way to use variable as the key in jsoncpp?


I wrote a function to save directory structure to json file.I'm using Jsoncpp libary to encode json.And I'm using c++17.But it throws a Json::LogicError. It says that "Json::Value::operator[](ArrayIndex) requires arrayValue".Here is the function:

void ScanFolder(string path)
{
        CTYPE::PFILELIST pfl;
        pfl=CTYPE::to(DIRVIEW::LoadDir(path));
        JSONFILE::Encode(DIRVIEW::AddPath(path,"fconfig.json"),pfl);
        for(const auto&ele : pfl.data)
                if(ele.type=="Folder")
                        ScanFolder(DIRVIEW::AddPath(pfl.current,ele.filename));
        return;
}

CTYPE,DIRVIEW and JSONFILE is namespaces defined by me.Here are the Encode function:

namespace JSONFILE
{
    void Encode(string filepath,CTYPE::PFILELIST data)
    {
        Json::StyledWriter writer;
        Json::Value arr,obj;
        fstream out;
        arr["Current_Folder"]=data.current;
        int i=0;
        for(const auto&ele : data.data)
        {
            arr["Files"][i]=ele.filename;
            obj["Type"]=ele.type;
            obj["Icon"]=ele.icon;
            arr[ele.filename]=obj;
            i++;
        }
        string jsonstr=writer.write(arr);
        out.open(filepath.c_str(),ios::binary|ios::out|ios::trunc);
        if(out.is_open())
            out<<jsonstr<<endl;
        else
            return;
        return;
    }
};

I found that the code witch caused the error is arr[ele.filename]=obj;.When I deleted it,the code works.I have checked the value of ele.filename,it isn't a empty variable and it have right value like 'filename.txt'.So what should I do to fix it?


Solution

  • It's what it says - you're trying to perform array indexing on something that is not an array.

    When you write arr["Files"], and arr is a Json::Value, a null object with that key is created for you:

    Access an object value by name, create a null member if it does not exist.

    So now you have a Json::Value called arr["Files"], which has the "null" type.

    But your next step was to treat it as an array, in arr["Files"][i]. That doesn't work; an array is not created for you:

    Access an array element (zero based index ).

    If the array contains less than index element, then null value are inserted in the array so that its size is index+1. (You may need to say 'value[0u]' to get your compiler to distinguish this from the operator[] which takes a string.)

    (Notice that this talks about auto-inserting elements, but not auto-creating the array itself.)


    This is really easy to fix; just make that object be an array:

    // ** New line here: **
    arr["Files"] = Json::Value(Json::arrayValue);
    
    for (const auto& ele : data.data)
    {
        arr["Files"][i] = ele.filename;
        obj["Type"] = ele.type;
        obj["Icon"] = ele.icon;
        arr[ele.filename] = obj;
        i++;
    }
    

    Here's what a minimal testcase for this issue looks like:

    #include <json/value.h>
    
    int main()
    {
        Json::Value val;
        val[0] = "foo";   // This throws Json::LogicError
    }