一、赋值问题
...
Value subServesObj(kObjectType);
subServesObj = subListObj["reserves"];
...
//subListObj是Document的某一个节点;
//如果进行了上述赋值操作,则Document中的"reserves"字段的value将为null。
char szName[64];
char szAge[64];
Value Name(kStringType);
Name.SetString(szName, strlen(szName));
subObject.AddMember("Name", Name, allocator);
Value age(kStringType);
age.SetString(szAge, strlen(szAge));
subObject.AddMember("age", Name, allocator);//注意此处
//Value Name(kStringType)被add之后,不能再次被AddMember;
//如果再次被AddMember,age对应的value为空。
二、接收到的json需要修改某些字段名或类型再发出去
内部 -> 我 -> 外部
如果以上json报文到我们的地方需要兼容字段,不要在原来的json上面进行Remove删除,再AddMember的操作,容易出现问题。
正确的操作方式是:重新建立一个document,将接收到的json报文进行解析,再将解析到的字段AddMember或PushBack到新document里。
Document doc;
doc.SetObject();
Document::AllocatorType& allocator = doc.GetAllocator();
//strRcvJson为一个数组类型的json
Document document
document.Parse(strRcvJson.c_str());
if (document.HasParseError())
{
printf("Parse strRcvJson failed!\n");
}
if(!document.IsArray())
{
printf(" strRcvJson document is not array\n");
}
Value SendRcvJsonArr(kArrayType);
for( auto &subObj : document.GetArray())
{
Value SendRcvJsonObj(kObjectType);
if(subObj.HasMember("time") && subObj["time"].IsInt64())
{
long iTime = subObj["time"].GetInt64();
Value time(kNumberType);
time.SetInt64(iTime);
SendRcvJsonObj.AddMember("time", time,allocator);
}
if(subObj.HasMember("ids") && subObj["ids"].IsArray())
{
Value SendIdsArr(kArrayType);
SendIdsArr = subObj["ids"];
SendRcvJsonObj.AddMember("ids", SendIdsArr, allocator);
}
if(subObj.HasMember("stringId") && subObj["stringId"].IsString())
{
string strStringId = subObj["stringId"].GetString();
Value stringId(kStringType); stringId.SetString(strStringId.c_str(),strStringId.size(),allocator);
SendRcvJsonObj.AddMember("stringId", stringId, allocator);
}
/*对于数组类型的value也可以这样解析添加,就是麻烦一点*/
if(subObj.HasMember("dataList") && subObj["dataList"].IsArray())
{
Value SendDataArr(kArrayType);
for( auto &subDataObj : subObj["dataList"].GetArray())
{
SendDataArr.PushBack(subDataObj, allocator);
}
SendRcvJsonObj.AddMember("dataList", SendDataArr, allocator);
}
SendRcvJsonArr.PushBack(SendRcvJsonObj,allocator);
}
doc.AddMember("sendJson", SendRcvJsonArr, allocator);
StringBuffer strBuffer;
Writer<StringBuffer>writer(strBuffer);
doc.Accept(writer);
string pcBuf = strBuffer.GetString();
三、可以将一个Document 通过AddMember或PushBack添加到另一个Document中
这种情况要注意一下待添加的Document的生命周期问题,局部变量释放了就有问题了,到最后doc.Accept(writer)会core掉。
四、深拷贝
在上文中我们提到过,rapidJson进行赋值操作,原节点value将变为空,有时我们不希望源原节点变为null,还需要用到原节点。
比如判断原节点的某些字段的值(过滤),再决定是否要将原节点添加到新的document,这时我们需要用到深拷贝。
Move语意
rapidjson的Move语意,请浏览http://rapidjson.org/zhcn/md_doc_tutorial_8zh-cn.html#MoveSemantics。
示例:
rapidjson::Value a(123);
rapidjson::Value b(456);
b = a; // a变成Null,b变成数字123,这样的做法是基于性能考虑
除了上述示例的复制语句外,AddMember()和PushBack()也采用了Move语意。深复制Value:
Value v1("foo");
// Value v2(v1); // 不容许
Value v2(v1, a); // 制造一个克隆,v1不变
Document d;
v2.CopyFrom(d, a); // 把整个document复制至v2,d不变
rapidjson为了最大化性能,大量使用了浅拷贝,使用之前一定要了解清楚。如果采用了浅拷贝,特别要注意局部对象的使用,以防止对象已被析构了,却还在被使用。
注:
1、当然,如果不用深复制,也可以暴力去解析此节点,再添加到新document。
2、如果仅仅是匹配字段,最好的方式是直接传引用,也不用深拷贝了,这个就看具体的场景了。
//传引用
Value &subObj = subListObj["object"];
//深拷贝
Document doc;//无特殊意义,用于reserves字段的深拷贝,为其提供内存分配器
Document::AllocatorType& allocator = doc.GetAllocator();
Value subObj(subListObj["object"], allocator)