JSON 解析方法和规则,读取 JSON 里面特定的值,JSON 类的继承关系
C++ Builder 自带的 JSON 头文件为 #include <System.JSON.hpp>,下图为 JSON 类的继承关系。
这是 C++ Builder 自带的 JSON 解析,第三方 jsoncpp 库的使用在这里
JSON 的解析,只需要调用 TJSONObject::ParseJSONValue() 函数,例如:
TJSONValue *lpJson = TJSONObject::ParseJSONValue(Memo1->Text);
这是把 Memo1->Text 的内容解析为 lpJson,这个解析之后的内容是在解析过程中 new 出来的,用完不要忘记 delete 掉。
在解析之后的数据里面,都是用 TJSONValue 这个公共的父类指针保存的数据,而实际的内容,可能是它的几个子类之一。
如上面框里面的代码,刚解析完的 lpJson 一般都是结构体类型的,即 TJSONObject,里面包含很多的成对的键名和键值,即 TJSONPair。
TJSONObject *lpRoot = dynamic_cast<TJSONObject *>(lpJson);
上面的代码,就是把第一段代码解析出来的 lpJson 转为 TJSONObject 类型的 lpRoot,即 JSON 的根节点,是一个结构体。
{
"name":"JSON测试程序,支持UNICODE哦",
"desc": "Copyright Victor Chen, ",
"strval": "中文Ting Vit",
"整数值": 12345,
"arrval":["人民币","欧元","英镑","$美元"],
"strarr":
[
{ "path": "fmn061/20111118/", "desc":"啊哦" },
{ "path": "abc/def/ghi", "desc": "abcd"}
]
}
假定有上面这一段 JSON 内容,用前面的代码解析到了 lpRoot 里面,然后要读取里面的值:
从结构体 (TJSONObject) 里面读出值来,直接用 Values[L"键名"] 就可以得到 TJSONValue * 类型的值,
如果 TJSONValue * 里面是单个值,用 Value() 可以简单的获取值到一个字符串里面,例如:
UnicodeString sName = lpRoot->Values[L"name" ]->Value();
UnicodeString sStrVal = lpRoot->Values[L"strval"]->Value();
UnicodeString sIntVal = lpRoot->Values[L"整数值"]->Value();
如果 TJSONValue * 里面是数组,要把这个类型转为 TJSONArray * 类型,用 Items[i] 读出第 i 个值,也是 TJSONValue * 类型的:
我们已经知道了 arrval 是数组,下面的代码简单的说明了数据类型的转换过程,读出 arrval[1] 的值:
红色部分,是强制转换 (因为我们已经知道是数组了) lpRoot->Values[L"arrval"] 转为 TJSONArray * 类型的。
UnicodeString sArrVal1 = ((TJSONArray*)(lpRoot->Values[L"arrval"]))->Items[1]->Value();
下面再看数组里面的元素是结构体的情况,读出 strarr[0].path 和 strarr[0].desc:
红色部分,是 strarr 转为 TJSONArray * 类型,蓝色是 strarr[0] 转为 TJSONObject * 类型的,然后读出 strarr[0].path 的值。
sStrArr0path = ((TJSONObject*)((TJSONArray*)(lpRoot->Values[L"strarr"]))->Items[0])->Values[L"path"]->Value();
sStrArr0desc = ((TJSONObject*)((TJSONArray*)(lpRoot->Values[L"strarr"]))->Items[0])->Values[L"desc"]->Value();
注意!以上三段代码仅仅是为大家介绍这些类型的转换规则,在实际应用中,这样做是不严谨的,容易出现错误。
最简单的,以这句代码为例:
UnicodeString sStrVal = lpRoot->Values[L"strval"]->Value();
如果 JSON 里面没有 strval 这个值,那么 lpRoot->Values[L"strval"] 是一个 NULL 值,再用 ->Value(); 就变成 “读取空指针” 错误了。
所以在实际应用中,每一步都要判断返回的 TJSONValue * 是否为 NULL 值,即那个键值是否存在。
所以,关键字可能会不存在,应该这样做:
TJSONValue *lpValue = lpRoot->Values[L"strval"];
if(lpValue) // 如果有 strval 这个关键字
{
sStrVal = lpValue->Value(); // 获取键值
}
TJSONValue
从 JSON 解析出来的值,都是使用 TJSONValue * 指针保存的,但是实际的内容,可能是它的以下子类之一:
TJSONObject 结构体,用它的成员 Values[L"键名"] 获取键值,一共有 Count 对键名/键值,第 i 对键名/键值为 Pairs[i]
TJSONArray 数组,用它的成员 Items[i] 获取第 i 个值,一共有 Count 个值
TJSONString 字符串,用它的成员 Value() 获取字符串值
TJSONNumber 数字,用 AsInt, AsInt64, AsDouble 获取整数或浮点数值,也可以用 Value() 获取值的字符串
TJSONBool 布尔,用 AsBoolean 获取 bool 值,也可以用 Value() 获取值的字符串。
TJSONBool 可能是它的子类 TJSONTrue 或 TJSONFalse 之一,用 dynamic_cast 可以转换或判断。
TJSONNull 空,它的成员 Value() 为从父类继承过来的,获取到空的字符串。
可以看到,只有 TJSONObject 和 TJSONArray 不能用 Value() 获取值,其他情况都能用 Value() 获取到正确的值,所以:
TJSONValue *lpJSONValue = 解析出来的值;
TJSONObject *lpJSONObject = dynamic_cast<TJSONObject *>(lpJSONValue);
TJSONArray *lpJSONArray = dynamic_cast<TJSONArray *>(lpJSONValue);
if(lpJSONObject)
{
// 按照结构体解析 lpJSONObject
}
else if(lpJSONArray)
{
// 按照数组解析 lpJSONArray
}
else
{
UnicodeString sValue = lpJSONValue->Value(); // 只要不是 TJSONObject 和 TJSONArray 就能用 Value() 获取到值
}
TJSONObject
TJSONObject 是结构体,是一组键名/键值的集合。