Search code examples
c++rapidjson

rapidjson - recursively change key value with nested field


I have a Json record with nested object and object arrays, the keys in those field contain spaces, I want to change all spaces to _, so I have to iterate all keys in the json object.

My idea is to write a depth first search to iterate all nested keys using ConstMemberIterator, my question is how can I change the key by given its iterator?

The example below represents my idea:

void DFSReplaceSpaceInKeys(Value::ConstMemberIterator& itr) {
    // Replace space in nested key
    std::string s(itr->name.GetString());
    std::replace(s.begin(), s.end(), ' ', '_');
    // set new string to key
    itr->name.SetString(s, ?.GetAllocator());  // <----- How can I get the document allocator?
    std::cout << "new key: " << itr->name.GetString() << std::endl;
    // recursive call in DFS
    if (itr->value.GetType() == Type::kObjectType) {
        DFSReplaceSpaceInKeys(itr->value.GetObject().MemberBegin());
    }
}

A Json record example:

{
   "a": {"b": [{"c": [...]}, {...}]
}

Solution

  • You can pass an allocator as parameter. I also think you should better pass Value& to represent a node.

    void DFSReplaceSpaceInKeys(Value& value, Value::AllocatorType& allocator) {
        if (value.IsObject()) {
            for (Value::ConstMemberIterator itr = value.MemberBegin(); itr != MemberEnd(); ++itr)
            {
                // Modify itr->name here...
                DFSReplaceSpaceInKeys(itr->value, allocator);
            }
        }
        else if (value.IsArray()) {
            for (Value::ConstIterator itr = value.Begin(); itr != value.End(); ++itr)
                DFSReplaceSpaceInKeys(*itr, allocator);
        }
    }
    
    // ...
    Document d;
    DFSReplaceSpaceInKeys(d, d.GetAllocator());
    

    If you only need to do the task as mentioned, you may just use the SAX API, which can be easier and faster. Check capitalize example.