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, http://www.cppfans.com/",
"strval": "中文한국어Tiếng Việt",
"整数值": 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 是结构体,是一组键名/键值的集合。
• 如果从 TJSONObject 里面读取键名为 KeyName 的键值来,可以用:
TJSONValue *lpKeyValue = lpJSONObject- >Values[L"KeyName"];
得到的是 lpKeyValue,这可能是一个结构体、数组、或者一个简单的数值。
• int iPairCount = lpJsonObject->Count; // 结构体里面一共有这些对键名/键值
TJSONPair *lpPair = lpJsonObject->Pairs[i]; // lpPair = 第 i 对键名/键值
UnicodeString sKeyName = lpPair->JsonString->Value(); // lpPair 的键名
TJSONValue *lpKeyValue = lpPair->JsonValue; // lpPair 的键值
TJSONPair
TJSONPair 是一对键名/键值,TJSONPair 经常用到的属性:
• JsonString: 是 TJSONString * 类型的,储存的键名,一般可以用 lpPair->JsonString->Value(); 得到 lpPair 的键名
• JsonValue: 是 TJSONValue * 类型的,这个键值可能是结构体、数组、或者一个简单的数值。
TJSONArray
TJSONArray 是一组键值,都是使用 TJSONValue * 储存的,Count 是键值的个数,Items[i] 是第 i 个键值。
for(int i=0; i<lpArray->Count; i++)
{
TJSONValue *lpItem = lpArray->Items[i];
// lpItem 可能是结构体、数组、或者简单的值
}
TJSONString
TJSONString 是一个简单的字符串值,用 Value() 获得字符串值。
TJSONNumber
TJSONNumber 是一个简单的数值,用 AsInt, AsInt64, AsDouble 获取整数或浮点数值,也可以用 Value() 获取值的字符串
TJSONBool / TJSONTrue / TJSONFalse
TJSONBool 是一个简单的布尔值,用 AsBoolean 获取 bool 值,也可以用 Value() 获取值的字符串。
TJSONBool 储存的值,可能是它的子类 TJSONTrue 或 TJSONFalse 之一,用 dynamic_cast 可以转换或判断。
TJSONNull
TJSONNull 是一个空值,它的成员 Value() 为从父类继承过来的,获取到空的字符串。
枚举 JSON 里面所有的值,JSON 的整体结构
void TForm1::EnumJsonValues(TJSONValue *lpJsonValue, UnicodeString sKeyName)
{
TJSONObject *lpJsonObject = dynamic_cast<TJSONObject *>(lpJsonValue);
if(lpJsonObject) // 结构体
{
for(int iPairIdx=0; iPairIdx<lpJsonObject->Count; iPairIdx++)
{
TJSONPair *lpPair = lpJsonObject->Pairs[iPairIdx]; // 第 iPairIdx 对键名/键值
UnicodeString sName = lpPair->JsonString->Value(); // 第 iPairIdx 对键名
TJSONValue *lpValue = lpPair->JsonValue; // 第 iPairIdx 对键值
// 不知道 lpValue 这个值是什么类型的,进一步枚举值,需要递归
EnumJsonValues(lpValue, sKeyName.IsEmpty()?sName:sKeyName+L"."+sName);
}
return;
}
TJSONArray *lpJsonArray = dynamic_cast<TJSONArray *>(lpJsonValue);
if(lpJsonArray) // 数组
{
for(int i=0; i<lpJsonArray->Count; i++) // 枚举数组里面每个元素
{
TJSONValue *lpValue = lpJsonArray->Items[i]; // 数组里面第 i 个元素
// 不知道 lpValue 这个值是什么类型的,进一步枚举值,需要递归
EnumJsonValues(lpValue, sKeyName+L"["+IntToStr(i)+L"]");
}
return;
}
// 既不是结构体,也不是数组,而是简单的单一值,可以直接输出
UnicodeString sKeyValue = lpJsonValue->Value(); // sKeyName 的值就是 lpJsonValue
Memo2->Lines->Add(sKeyName + L" = " + sKeyValue);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TJSONValue *lpJson = TJSONObject::ParseJSONValue(Memo1->Text);
if(lpJson)
{
EnumJsonValues(lpJson, L"");
delete lpJson;
}
}
//--------------------------------------------------------------------------- |
运行结果:
生成 JSON 字符串/文件
例1:
TJSONObject *lpJson = new TJSONObject;
lpJson->AddPair(L"name" , "Victor Chen");
lpJson->AddPair(L"homepage", L"http://www.cppfans.com/");
Memo2->Text = lpJson->ToJSON();
delete lpJson; |
执行的结果:
{"name":"Victor Chen","homepage":"http:\/\/www.cppfans.com\/"} |
例2:
void __fastcall TForm1::Button3Click(TObject *Sender)
{
TJSONObject *lpJson = new TJSONObject;
lpJson->AddPair(L"name", "Victor Chen");
lpJson->AddPair(L"homepage", L"www.cppfans.com");
TJSONArray *lpStrings= new TJSONArray;
lpStrings->Add(UnicodeString(L"Victor" ));
lpStrings->Add(UnicodeString(L"Michael"));
lpStrings->Add(UnicodeString(L"Jack" ));
lpJson->AddPair(L"Strings", lpStrings);
TJSONArray *lpNumbers = new TJSONArray;
lpNumbers->Add(123);
lpNumbers->Add(456);
lpNumbers->Add(7890);
lpJson->AddPair(L"Numbers", lpNumbers);
Memo2->Text = lpJson->ToString();
delete lpJson;
} |
执行的结果:
{"name":"Victor Chen","homepage":"www.cppfans.com","Strings":["Victor","Michael","Jack"],"Numbers":[123,456,7890]} |
|