How to copy a rapidjson::Value using rapidjson::writer? I found several solutions when using a Document - but not when using a writer.
E.g.: How can I add members to a rapidjson document using integers as the key/name?
So, I want something like this to work:
rapidjson::CrtAllocator _crtAllocator;
rapidjson::GenericStringBuffer<rapidjson::UTF8<>> _jsonBuffer;
rapidjson::PrettyWriter<rapidjson::StringBuffer> _jsonWriter;
void GeojsonWriter::addMember(std::string name, rapidjson::Value& value) {
_jsonWriter.AddMember(name, value, _crtAllocator);
}
An example usage is in my case to copy the "properties" object of a Geojson feature to another feature (which was created from a different geometry, but should be assigned a copy of the "original" properties)
I've implemented the method as in the answer below. Though I face random crashes when accessing itr->name.GetString() below. The crash leads to std string... Though sometimes the same data works fine. This looks much like a memory allocation issue - but I have no trails where to look at.
Crash in std string here (though less relevant probably): static inline size_t length(const char_type* __s) {return strlen(__s);}
void copyGeojsonProperties(GeojsonWriter &writer, const rapidjson::Value* properties) {
for (rapidjson::Value::ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) {
if (itr->name.IsString()) {
const char* cstr = itr->name.GetString();
if (!cstr || !itr->name.Empty())
continue;
std::string key = itr->name.GetString();
const rapidjson::Value& val = itr->value;
writer.addMember(key, val);
}
}
}
I found a workaround. I have multiple input json documents form where I use value.CopyFrom(..., document.GetAllocator()). The issue was that the document was freed when the json was read (I copy objects from different jsons, and later write them into another json). Now I keep a reference to the pointer, to prevent the allocator being freed.
It isn't obvious though that it's required to keep the allocator around even when the value was copied.
If the writer has already been called StartObject()
, then you only need to:
void GeojsonWriter::addMember(const std::string& name, const rapidjson::Value& value) {
_jsonWriter.Key(name.c_str(), name.size());
value.Accept(_jsonWriter);
}