主页C++ Builder 资料C++ Builder 编程技巧文件处理JSON 解析和生成
C++ Builder 串口控件
C++ Builder 编程技巧
字符串及文字处理
多媒体处理
图片处理
文件处理
 • INI 文件处理
 • JSON 解析和生成
 • CHM 帮助文件
界面处理
C++ Builder 操作指南
C++ Builder 参考手册
网友留言/技术支持
JSON 解析和生成 - 文件处理
 • JSON 解析方法和规则,读取 JSON 里面特定的值,JSON 类的继承关系
 • JSON 类 TJSONValue|TJSONObject|TJSONPair|TJSONArray|TJSONString|TJSONNumber|TJSONBool|TJSONTrue|TJSONFalse|TJSONNull
 • 枚举 JSON 里面所有的值,JSON 的整体结构
 • 生成 JSON 字符串/文件

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]}
◤上一页:INI 文件处理下一页:CHM 帮助文件

C++ 爱好者 -- Victor Chen 的个人网站 www.cppfans.com 辽ICP备11016859号