RapidJson中的GetValueByPointer用法
RapidJson 中的GetValueByPointer用法
{
"person": {
"name": "Lucy",
"age": 22,
"address": {
"province": "广东",
"city": "深圳",
"street": "深南大道"
}
}
}
假如有这样一段json,想要解析出人名和省份,那么有一下方法
HasMember
rapidjson::Document doc;
if (doc.Parse(str.c_str()).HasParseError())
{
cout << "json error" << endl;
}
string name;
string province;
if (doc.HasMember("person") and doc["person"].IsObject())
{
rapidjson::Value &person = doc["person"];
if (person.HasMember("name") and person["name"].IsString())
{
name = person["name"].GetString();
}
if (person.HasMember("address") and person["address"].IsObject())
{
rapidjson::Value &address = person["address"];
if (address.HasMember("province") and address["province"].IsString())
{
province = address["province"].GetString();
}
}
}
cout << name << " live at " << province << endl;
为什么要写的这么复杂?我们直接doc["person"]["name"]
不行吗?很遗憾,的确不行。相信大家都对这个assert深受其害,所有在使用rapidjson解析的时候需要严格的做好类型判断,一不小心程序就assert了。如果每次获取前都需要先判断元素在不在,然后再判断元素的类型,那这样写起来太复杂了,这时候就出现了GetValueByPointer
GetValueByPointer
GetValueByPointer
接受一个用/分割的字符串列表,表示从doc中查找的目录,比如GetValueByPointer(doc, "/person/address/province");
表示以doc为根目录查找person>address>province字段,返回一个指针,通过指针就能找到该字段。
rapidjson::Document doc;
if (doc.Parse(str.c_str()).HasParseError())
{
cout << "json error" << endl;
}
string name;
string province;
rapidjson::Value *pName = GetValueByPointer(doc, "/person/name");
if (pName != NULL and pName->IsString())
{
name = pName->GetString();
}
rapidjson::Value *pProvince = GetValueByPointer(doc, "/person/address/province");
if (pProvince != NULL and pProvince->IsString())
{
province = pProvince->GetString();
}
cout << name << " live at " << province << endl;
这样就不用每次在找一个节点的时候判断它的父节点是否存在,而且也不用判断父节点类型了。
FindMember
其实和GetValueByPointer
的功能和FindMember
是相似的,只不过是简化了,操作如下:
rapidjson::Document doc;
if (doc.Parse(str.c_str()).HasParseError())
{
cout << "json error" << endl;
}
string name;
string province;
rapidjson::Value::ConstMemberIterator iter1 = doc.FindMember("person");
if (iter1 != doc.MemberEnd())
{
const rapidjson::Value &v = iter1->value;
rapidjson::Value::ConstMemberIterator iter2 = v.FindMember("name");
if (iter2 != v.MemberEnd() and iter2->value.IsString())
{
name = iter2->value.GetString();
rapidjson::Value::ConstMemberIterator iter3 = v.FindMember("address");
if (iter3 != v.MemberEnd() and iter3->value.IsObject())
{
rapidjson::Value::ConstMemberIterator iter4 = iter3->value.FindMember("province");
if (iter4 != iter3->value.MemberEnd() && iter4->value.IsString())
{
province = iter4->value.GetString();
}
}
}
}
cout << name << " live at " << province << endl;
用FindMember
也能达到目的。通常来说,我们更愿意使用GetValueByPointer
,它让代码更加简洁易读。
GetValueByPointerWithDefault
在一些语言中,当用[]访问map时,如果map有key,则返回value,否则插入空,再返回。rapidjson也提供了类似接口,而且还可以指定缺省值
Value&title=GetValueByPointerWithDefault(d,"/widget/window/title","untitled");
当解引用失败时,它会创建整个路径,并把预设值复制成新值,并返回该值。由于它总能返回一个值,此函数的返回类型为引用而不是指针。
CreateValueByPointer
这绝对是操作神器,可以快速创建json的层级节点,并且返回该节点,CreateValueByPointer(d,"/a").SetArray();
,这样就能创建一个节点了。特别的,当层级token以负号"-"结尾时,他可以指向JSONArray最后元素的下一个元素,利用这种特性可以实现PushBack的效果。
rapidjson::Document d;
CreateValueByPointer(d,"/a").SetArray();
for(int i = 1; i <=4 ;i ++)
{
//SetValueByPointer(d,"/a/-", i);
CreateValueByPointer(d,"/a/-").SetInt(i);
}
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
d.Accept(writer);
cout << buffer.GetString() << endl;
最后输出{"a":[1,2,3,4]}
,这样就达到了数组PushBack的效果了~
上一篇: C++智能指针
下一篇: redis主从复制过程原理