【问题标题】:Delphi / REST / JSON德尔福/REST/JSON
【发布时间】:2017-09-15 14:39:48
【问题描述】:

我正在使用 Delphi Tokyo 10.2 Update 1 和 RESTRequest、RESTResponse 和 RESTClient 组件与 REST 服务器进行通信。这是我第一次尝试使用 REST/JSON。

我已成功发送登录请求 (POST) 并收到预期的响应 (GUID)。然后我使用 GUID 执行各种其他请求 (GET)。发出的两个请求发回一个空文件和文档 JSON 模板,然后我必须对其进行填充。这就是我卡住的地方。我不确定在 JSON 对象中更新属性值的最佳方式。

这是我返回的空 JSON 文件模板:

{
  "boxId": 0,
  "changedBy": 0,
  "customSort": "",
  "dateChanged": "1990-01-01T00:00:00",
  "dateStarted": "1990-01-01T00:00:00",
  "destruction": "1990-01-01T00:00:00",
  "documentCount": 0,
  "documents": {
    "TotalCount": 0,
    "Collection": [

    ]
  },
  "extraData": {
    "TotalCount": 0,
    "Collection": [

    ]
  },
  "fieldDefs": {
    "TotalCount": 0,
    "Collection": null
  },
  "field": [
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    ""
  ],
  "fileId": 0,
  "filePtr": 0,
  "id": 0,
  "isIndexed": false,
  "keyValue": "",
  "keyVisualValue": "",
  "labelPrinted": "1990-01-01T00:00:00",
  "lineItems": {
    "TotalCount": 0,
    "Collection": [

    ]
  },
  "notes": "",
  "objectType": 5,
  "projectId": 0,
  "routeInfo": null,
  "routingDoc": null,
  "remoteId": 0,
  "saveNotesOnly": false,
  "saveStyle": -999,
  "status": 1,
  "syncFlag": 0,
  "totalDocumentCount": 0,
  "viewerContext": 0
}

在 Python 中填充字段属性数组中的前两个值,我只需这样做:

inc_filetemplate = json.loads(requests.get(NEWFILE_string).text)
inc_doctemplate = json.loads(requests.get(NEWDOC_string).text)
filetemplate = inc_filetemplate
doctemplate = inc_doctemplate
filetemplate['field'][1] = dcn
filetemplate['field'][2] = batchname

简单!!!! ;)

使用 Delphi 执行此操作的最佳方法是什么?

我可以从“字段”数组中获取值(本示例中的前两项恰好为空)。只是不确定为这些项目设置值的最佳方式。

这是我开始的:

procedure PopulateFileTemplate(const AFileTemplate: String);
var
  JO: TJSONObject;
  JOPair: TJSONPair;
  JOArray: TJSONArray;
  FieldDCN: String;
  FieldBatchName: String;

begin
  JO := TJSONObject.ParseJSONValue(AFileTemplate) as TJSONObject;

  try
    if JO = nil then
    begin
      MessageDlg('Unable to parse JSON file template.', mtError, [mbOK], 0);

      Exit;
    end;

    JOArray := JO.Get('field').JsonValue as TJSONArray;
    FieldDCN := JOArray.Items[0].Value;
    FieldBatchName := JOArray.Items[1].Value;

    Memo1.Lines.Add('The old value of DCN is: ' + FieldDCN);
    Memo1.Lines.Add('The old value of BatchName is: ' + FieldBatchName);

    // Best way to set Values here???????

    Memo1.Lines.Add('The new value of DCN is: ' + FieldDCN);
    Memo1.Lines.Add('The new value of BatchName is: ' + FieldBatchName);
  finally
    JO.Free;
  end;
end;

【问题讨论】:

  • 你需要选择一个JSON库,比如Super Object。
  • Delphi 在 RTL 中也有自己的 JSON framework
  • 我已经查看并使用了 RTL 中内置的 JSON 框架。但是,要么我做的不对,要么你不能像使用 Python 那样直接设置 JSON 属性值。我会继续玩 JsonTextReader 和 JsonTextWriter。
  • 阅读文档
  • 我已阅读文档,@DavidHeffernan。解析和检索值不是问题。设置它们是我遇到问题的地方。并不是说不能做。我在这里看到了例子。我只是很惊讶德尔福没有更好的方法来做到这一点。非常难看。从上面的 Python 源代码中可以看到,它非常简单。 ;) 感谢您的回复。

标签: json rest delphi


【解决方案1】:

TJSONArray.Items[] 属性返回一个TJSONValue,在您的示例中是TJSONString 对象,因为fields 是一个字符串数组。

TJSONArray 实际上并非旨在允许修改数组中的现有 对象。您可以将新对象添加到数组的末尾,并从数组中删除任意对象,但您不能在任意索引处插入新对象,也不能用新对象替换现有对象。

最接近这种功能的方法是构造一个包含所需对象的TList<TJSONValue>,然后将其传递给TJSONArray.SetElements()。不理想。

并且TJSONString 没有任何方法或属性来编辑其string 值(TJSONString.AddChar() 除外)。

您可以尝试使用访问器/帮助器类来访问受保护的TJSONString.FStrBuffer 成员,然后根据需要编辑其内容:

type
  TJSONStringAccess = class(TJSONString)
  end;

procedure SetJSONStringValue(JSONValue: TJSONString; const S: string);
begin
  with TJSONStringAccess(JSONValue) do
  begin
    FStrBuffer.Clear;
    FStrBuffer.Append(S);
  end;
end;

procedure PopulateFileTemplate(const AFileTemplate: String);
var
  JO: TJSONObject;
  JOPair: TJSONPair;
  JOArray: TJSONArray;
  FieldDCN: TJSONString;
  FieldBatchName: TJSONString;
begin
  JO := TJSONObject.ParseJSONValue(AFileTemplate) as TJSONObject;
  if JO = nil then
  begin
    MessageDlg('Unable to parse JSON file template.', mtError, [mbOK], 0);
    Exit;
  end;
  try
    JOArray := JO.Get('field').JsonValue as TJSONArray;
    FieldDCN := JOArray.Items[0] as TJSONString;
    FieldBatchName := JOArray.Items[1] as TJSONString;

    Memo1.Lines.Add('The old value of DCN is: ' + FieldDCN.Value);
    Memo1.Lines.Add('The old value of BatchName is: ' + FieldBatchName.Value);

    SetJSONStringValue(FieldDCN, '...');
    SetJSONStringValue(FieldBatchName, '...');

    Memo1.Lines.Add('The new value of DCN is: ' + FieldDCN.Value);
    Memo1.Lines.Add('The new value of BatchName is: ' + FieldBatchName.Value);
  finally
    JO.Free;
  end;
end;

type
  TJSONStringHelper = helper class for TJSONString
    procedure SetValue(const S: string);
  end;

procedure TJSONStringHelper.SetValue(const S: string);
begin
  Self.FStrBuffer.Clear;
  Self.FStrBuffer.Append(S);
end;

procedure PopulateFileTemplate(const AFileTemplate: String);
var
  JO: TJSONObject;
  JOPair: TJSONPair;
  JOArray: TJSONArray;
  FieldDCN: TJSONString;
  FieldBatchName: TJSONString;
begin
  JO := TJSONObject.ParseJSONValue(AFileTemplate) as TJSONObject;
  if JO = nil then
  begin
    MessageDlg('Unable to parse JSON file template.', mtError, [mbOK], 0);
    Exit;
  end;
  try
    JOArray := JO.Get('field').JsonValue as TJSONArray;
    FieldDCN := JOArray.Items[0] as TJSONString;
    FieldBatchName := JOArray.Items[1] as TJSONString;

    Memo1.Lines.Add('The old value of DCN is: ' + FieldDCN.Value);
    Memo1.Lines.Add('The old value of BatchName is: ' + FieldBatchName.Value);

    FieldDCN.SetValue('...');
    FieldBatchName.SetValue('...');

    Memo1.Lines.Add('The new value of DCN is: ' + FieldDCN.Value);
    Memo1.Lines.Add('The new value of BatchName is: ' + FieldBatchName.Value);
  finally
    JO.Free;
  end;
end;

否则,请考虑切换到本机支持编辑值的第 3 方 JSON 库。如SuperObject

【讨论】:

  • 谢谢。似乎 SuperObject 可能是更好的选择。在我的研究中,我确实看到有人使用它。现在正在下载。再次感谢!
猜你喜欢
  • 2014-11-01
  • 2014-07-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-02
  • 2011-10-04
相关资源
最近更新 更多