如何使用Delphi Tokyo 10.2解析来自Dynamics的OData结果?
先看看你提供的Dynamics CRM Web API返回的OData示例数据:
{ "@odata.context":"https://myurl.dynamics.com/api/data/v8.0/$metadata#bookableresources(_userid_value)","value":[ { "@odata.etag":"W/"40599496"","_userid_value":"1648251b-9bff-e611-8107-c4346bc50748","bookableresourceid":"83bf299a-ac3b-e811-8161-e0071b670e51" },{ "@odata.etag":"W/"40599510"","_userid_value":"cbd8b90f-9cff-e611-8109-c4346bc5c21c","bookableresourceid":"0a29b027-ad3b-e811-8161-e0071b670e51" },{ "@odata.etag":"..." } ] }
针对这个JSON结构,我给你整理了三种在Delphi Tokyo 10.2里的实用解析方案,你可以根据项目需求选:
方案一:用Delphi内置JSON类库
Delphi Tokyo自带System.JSON单元,不用第三方库就能搞定。步骤如下:
- 项目里引用
System.JSON单元 - 解析代码示例:
uses System.JSON; procedure ParseDynamicsOData(const JSONStr: string); var RootObj: TJSONObject; ValueArray: TJSONArray; ItemObj: TJSONObject; I: Integer; ODataContext, ETag, UserId, ResourceId: string; begin // 解析根JSON对象 RootObj := TJSONObject.ParseJSONValue(JSONStr) as TJSONObject; try // 获取@odata.context字段 ODataContext := RootObj.GetValue<string>('@odata.context'); Writeln('OData Context: ', ODataContext); // 获取资源数组 ValueArray := RootObj.GetValue<TJSONArray>('value'); if Assigned(ValueArray) then begin // 遍历每个资源对象 for I := 0 to ValueArray.Count - 1 do begin ItemObj := ValueArray.Items[I] as TJSONObject; if Assigned(ItemObj) then begin // 提取字段值(如果字段可能不存在,建议用TryGetValue避免报错) ItemObj.TryGetValue('@odata.etag', ETag); ItemObj.TryGetValue('_userid_value', UserId); ItemObj.TryGetValue('bookableresourceid', ResourceId); // 这里可以按需处理数据,比如存入列表或显示 Writeln('--- 资源', I+1, ' ---'); Writeln('ETag: ', ETag); Writeln('User ID: ', UserId); Writeln('Resource ID: ', ResourceId); end; end; end; finally RootObj.Free; end; end;
方案二:用SuperObject第三方库
SuperObject是Delphi圈里超流行的JSON解析库,语法更简洁,还自动管理内存。你可以通过Delphi的GetIt包管理器直接安装它。
解析代码示例:
uses SuperObject; procedure ParseDynamicsODataWithSuperObject(const JSONStr: string); var SO: ISuperObject; Item: ISuperObject; begin SO := SOParse(JSONStr); if Assigned(SO) then begin // 获取@odata.context Writeln('OData Context: ', SO.S['@odata.context']); // 遍历资源数组,代码比内置库紧凑很多 for Item in SO.A['value'] do begin Writeln('--- 资源 ---'); Writeln('ETag: ', Item.S['@odata.etag']); Writeln('User ID: ', Item.S['_userid_value']); Writeln('Resource ID: ', Item.S['bookableresourceid']); end; end; end;
方案三:类映射(面向对象方式)
如果项目频繁处理这类数据,定义实体类做映射会让代码更易维护,结构也更清晰。
首先定义对应数据结构的实体类:
uses System.JSON.Serializers; type TBookableResource = class private [JSONName('@odata.etag')] FETag: string; [JSONName('_userid_value')] FUserIdValue: string; [JSONName('bookableresourceid')] FBookableResourceId: string; public property ETag: string read FETag write FETag; property UserIdValue: string read FUserIdValue write FUserIdValue; property BookableResourceId: string read FBookableResourceId write FBookableResourceId; end; TDynamicsODataResponse = class private [JSONName('@odata.context')] FODataContext: string; FValue: TArray<TBookableResource>; public property ODataContext: string read FODataContext write FODataContext; property Value: TArray<TBookableResource> read FValue write FValue; destructor Destroy; override; end; destructor TDynamicsODataResponse.Destroy; var Resource: TBookableResource; begin for Resource in FValue do Resource.Free; inherited; end;
然后用TJSONSerializer完成解析:
uses System.JSON.Serializers; procedure ParseDynamicsODataWithMapping(const JSONStr: string); var Serializer: TJSONSerializer; Response: TDynamicsODataResponse; Resource: TBookableResource; begin Serializer := TJSONSerializer.Create; try Response := Serializer.Deserialize<TDynamicsODataResponse>(JSONStr); try Writeln('OData Context: ', Response.ODataContext); for Resource in Response.Value do begin Writeln('--- 资源 ---'); Writeln('ETag: ', Resource.ETag); Writeln('User ID: ', Resource.UserIdValue); Writeln('Resource ID: ', Resource.BookableResourceId); end; finally Response.Free; end; finally Serializer.Free; end; end;
内容的提问来源于stack exchange,提问作者SiBrit

