////////////////////////////////////////////////////////////////////////////
//1. Parse a JSON text string to a document.
const char json[] =
"{"
"\"name\": \"Obama\","
"\"null\": null,"
"\"int\": 6,"
"\"double\": 3.14,"
"\"bool\": true,"
"\"array\": [5,6,7,8]"
"}";
/**
*json的数据类型有number,String,null,bool。Object,array
number可以是任何类型数字,数组的成员也可以是任何类型。由于c++
的限制,我们会在解析器中扩展出number的int,unsigned int,double,等等
他们都属于number.
json的键只可以是String。不管什么类型的数据,亦或是键,他们都属于value类型
*/
Document document;
document.Parse(json);//解析
assert(!document.HasParseError());//查看是否有创建错误
//遍历表
for (auto b =document.MemberBegin(); b != document.MemberEnd(); ++b)
{
std::cout <<b->name.GetString()<<" ";//键依然是value类型
std::cout <<b->value.IsArray()<<b->value.IsNumber()<<b->value.IsString()<<b->value.IsBool();//可以发现json的值都保存在Value中
}
std::cout <<std::endl;
/************************************************************************/
/* 跟节点的数据类型
早期的json版本,根节点数据只可以是数组或者Object,不过在最新版的json
中,支持所有类型作为根节点
*/
/************************************************************************/
assert(document.IsObject());
//assert(document.IsArray());导致断言
/************************************************************************/
/*索引值
支持下标和find操作
下标强制返回value的引用,find 返回键值对的迭代器
auto & ref =document["name"];
auto iter =document.findMember("name");
*/
/************************************************************************/
auto& ref = document["name"];//强制引用
auto iter =document.FindMember("name");
std::cout <<ref.GetString()<<std::endl;
std::cout << iter->name.GetString() <<iter->value.GetString();//迭代了键值对,name是一个固定String类型的value
std::cout <<std::endl;
/************************************************************************/
/* 获取值
可以用value::get***函数来获取value的具体值
*/
/************************************************************************/
/************************************************************************/
/* 判断值
Value::is***函数来判断具体类型
*/
/************************************************************************/
/************************************************************************/
/*
设定值
Value::set***可以设定修改某个键的值,值的类型可以变.
document也是一个Value。
document在建立之初,我们可以为之设定一个初始值
document.SetObject();
*/
/************************************************************************/
auto& dou =document["double"];
dou.SetString("3.14");
/************************************************************************/
*/
/************************************************************************/
auto& arr =document["array"];
for (auto b = arr.Begin(); b != arr.End(); ++b)//数组的成员依然是value,并且数据结构是Vector
{
std::cout<< b->GetInt();
}
for (int i = 0; i < arr.Size(); ++i)//既然是vector,那么就支持下标操作
{
arr[i].SetInt(6);
}
//插入弹出--popBack
arr.PushBack(8/*创建一个Value*/,document.GetAllocator());//显示传递内存分配器,一般标准库容器作为模板实参,其默认值都会失效
arr.PushBack(Value("啦啦啦"),document.GetAllocator());
//我们需要显式指定allocator
/************************************************************************/
/* 数字
数字在调用getdouble时候会发生自动转换。对于int,unsigned int,double,可以无损转换
但是int64会使数据丢失*/
/************************************************************************/
std::cout <<std::endl;
/************************************************************************/
/* 比较
很幸运的是,value重载了== !=比较操作符,于是我们不必麻烦的用get函数之后再比较*/
/************************************************************************/
bool isS = ref =="Obama";//true
dou.SetDouble(3.14);
bool isD = dou != 3;
/************************************************************************/
/*Value的右值语意
对于value的赋值操作符 =
addMember
pushBack
他们的参数都是一个右值引用,于是,原来的值会被搬移到新的地方,而原来的值会变成null
对于现代的编译器,他们大多数都会有右值的优化,如果函数返回一个临时对象,外边还有人接受的话
那么就会由默认的右值语意,对于函数的形参也是一个道理。不过对于返回一个局部对象的话,这样必定会产生拷贝
在面对较大的拷贝时候,我们可以用std::move()函数显式的将局部对象转换成右值。
*/
/************************************************************************/
Valueo(kObjectType);
{
Valuecontacts(kArrayType);
//adding elements to contacts array.
o.AddMember("contacts",contacts,document.GetAllocator()); //给Object添加成员
}
/************************************************************************/
/* String
*/
/************************************************************************/
Value v;
v.SetString("hello");//静态创建文本.默认调用strlen获得字符串长度
char buffer[10] ={0};
size_tlen = sprintf(buffer,"%s","hello");//动态文本
v.SetString(buffer,len);
//于是乎我们可以动态的创建一个document成员
document.AddMember(v,"啦啦啦啦啦啦啦",document.GetAllocator());
/************************************************************************/
/* 我需要深度拷贝
不能用=操作符,我如何拷贝?
*/
/************************************************************************/
{
Documentd;
Document::AllocatorType&a = d.GetAllocator();
Valuev1("foo");
//Value v2(v1); // not allowed
Value v2(v1,a); //构造拷贝
assert(v1.IsString()); // v1 untouched
d.SetArray().PushBack(v1,a).PushBack(v2,a); // 右值语意
assert(v1.IsNull()&& v2.IsNull());
v2.CopyFrom(d,a); // 构造拷贝第二种方法
assert(d.IsArray()&& d.Size() == 2); // d untouched
v1.SetObject().AddMember("array",v2,a);//右值语意
d.PushBack(v1,a);//右值语意
assert(v1.IsNull()&& v2.IsNull());
}
/************************************************************************/
/* 交换值*/
/************************************************************************/
{
Valueaa(123);
Valuebb("Hello");
aa.Swap(bb);
assert(aa.IsString());
assert(bb.IsInt());
}