【问题标题】:Delphi pointer variable required需要 Delphi 指针变量
【发布时间】:2018-02-20 06:21:28
【问题描述】:

我正在尝试创建一个可以将 JSON 字段动态附加到主要 JSON 对象的全局过程。

procedure TJSONAdapter.addField(Key, Field: String);
var
  i: Integer;
  strArr: TStringList;
  j: Integer;

  pJSONObj: ^TJSONObject;
begin
  strArr:= TStringList.Create;
  Split('.', Key, strArr);

  pJSONObj:= @STATICJSON;

  i:= 0;
  repeat
  begin
    if IsSimpleJsonValue(STATICJSON.GetValue(strArr[i])) then
    begin
      Exit;
    end;

    if STATICJSON.GetValue(strArr[i]) is TJSONObject then
    begin
      pJSONObj:= @(STATICJSON.GetValue(strArr[i]) as TJSONObject); -> error in this line
      if i + 1 = strArr.Count then
      begin

我将我的值存储在一个名为 STATICJSON 的 JSON 对象中,直到程序关闭,然后我将其保存到文件中。

我正在尝试在STATICJSON 的某处添加一个字段。例如;

{
  "colors" :
    {
      "id": "F00",
      "color": "red",
      "details" : [
        {
         "name_en": "Red",
        },
        {
         "name_de": "Rot"
        }
      ]
   },
   {
      "id": "0F0",
      "color": "green",
      "details" : [
        {
         "name_en": "Green",
        },
        {
         "name_de": "Grün"
        }
      ]
   }
 }

如果我想在colors 数组中第一个对象的每个details 中添加一个code 字段:

obj.addField('colors.0.details.X', 'code');

我的预期:

{
  "colors" :
    {
      "id": "F00",
      "color": "red",
      "details" : [
        {
         "name_en": "Red",
         "code": ""
        },
        {
         "name_de": "Rot",
         "code": ""
        }
      ]
   },
   {
      "id": "0F0",
      "color": "green",
      "details" : [
        {
         "name_en": "Green",
        },
        {
         "name_de": "Grün"
        }
      ]
   }
 }

所以我正在尝试使用指针转到第一种颜色的details 数组和addField

我正在使用:

STATICJSON:= STATICJSON.GetValue(strArr[i]) as TJSONObject;

而且效果很好,但是STATICJSON的内容变成了这样:

"details" : [
            {
             "name_en": "Red",
             "code": ""
            },
            {
             "name_de": "Rot",
             "code": ""
            }
          ]

所以我丢失了所有其他 JSON 内容。这就是我想使用指针的原因。但是我在这一行遇到了一个错误:

pJSONObj:= @(STATICJSON.GetValue(strArr[i]) as TJSONObject);

需要变量

更新:

procedure TJSONAdapter.addField(Key, Field: String);
var
  i: Integer;
  strArr: TStringList;
  j: Integer;

begin

  strArr:= TStringList.Create;
  Split('.', Key, strArr);

  i:= 0;
  repeat
  begin
    if IsSimpleJsonValue(STATICJSON.GetValue(strArr[i])) then
    begin
      Exit;
    end;

    if STATICJSON.GetValue(strArr[i]) is TJSONObject then
    begin
      STATICJSON:= STATICJSON.GetValue(strArr[i]) as TJSONObject;
      if i + 1 = strArr.Count then
      begin
        STATICJSON.AddPair(TJSONPair.Create(Field, ''));
        Exit;
      end;
    end;

    if STATICJSON.GetValue(strArr[i]) is TJSONArray then
    begin
      if strArr[i + 1] = 'X' then
      begin
        for j := 0 to (STATICJSON.GetValue(strArr[i]) as TJSONArray).Size -1 do
        begin
          ((STATICJSON.GetValue(strArr[i]) as TJSONArray).Get(j) as TJSONObject).AddPair(TJSONPair.Create(Field, ''));
        end;
        Exit;
      end;

      STATICJSON:= (STATICJSON.GetValue(strArr[i]) as TJSONArray).Get(StrToInt(strArr[i+1])) as TJSONObject;
      i:= i+1;

    end;
    Inc(i);
  end;
  until i = strArr.Count;

  strArr.Free;
end;

它可以工作,但是因为这些行:

STATICJSON:= STATICJSON.GetValue(strArr[i]) as TJSONObject;

STATICJSON:= (STATICJSON.GetValue(strArr[i]) as TJSONArray).Get(StrToInt(strArr[i+1])) as TJSONObject;

我丢失了主要的 JSON 内容,所以我不想分配STATICJSON,我只想将其地址分配给一个指针以不丢失其内容。

【问题讨论】:

  • 你为什么要那个指针的东西? TJSONObject 已经是一个指针,指向一个对象。所以,为了确定,你需要一个指向指针的指针吗?
  • @Victoria 好的,但我如何更改 tjsonobject 中 json 的内容?在用户向我发送输入之前,我不知道哪个字段会改变。我也不知道 json 的内容。
  • @Nevermore 只需通过调用改变其状态的方法来改变它。例如。 AddPairSetPairsRemovePair

标签: json delphi delphi-xe5


【解决方案1】:

Delphi 对象是引用类型。 TJSONObject已经是一个指针,所以不用^TJSONObject

试试这样的:

var
  STATICJSON: TJSONObject = nil;

procedure TJSONAdapter.addField(Key, Field: String);
var
  I, J, Index: Integer;
  strArr: TStringList;
  pJSONVal: TJSONValue;
begin
  strArr := TStringList.Create;
  try
    Split('.', Key, strArr);
    if STATICJSON = nil then begin
      STATICJSON := TJSONObject.Create;
    end;
    pJSONVal := STATICJSON;
    For I := 0 to strArr.Count-1 then
    begin
      if TryStrToInt(strArr[I], Index) then
      begin
        if not (pJSONVal is TJSONArray) then Exit; 
        pJSONVal := TJSONArray(pJSONVal).Get(Index);
      end
      else if strArr[I] = '*' then
      begin
        if I <> (strArr.Count-1) then Exit;
        if not (pJSONVal is TJSONArray) then Exit; 
        with TJSONArray(pJSONVal) do
        begin
          For J := 0 to Count-1 do
          begin
            pJSONVal := Get(Index);
            if pJSONVal is TJSONObject then
              TJSONObject(pJSONVal).AddPair(Field, '');
          end;
        end;
      end
      else if pJSONVal is TJSONObject then
      begin
        pJSONVal := TJSONObject(pJSONVal).Get(strArr[I]);
        if pJSONVal = nil then Exit;
      end
      else Exit;
    end;
    if pJSONVal is TJSONObject then
      TJSONObject(pJSONVal).AddPair(Field, '');
  finally
    strArr.Free;
  end; 
end;

obj.addField('colors.0.details.*', 'code');

【讨论】:

  • Remyyyyyy 我爱你,非常感谢你,你是大师。谢谢你,谢谢你,谢谢你。我正在研究它超过 2 天。我将最后一行更改为: TJSONObject(pJSONVal).AddPair(TJSONPair.Create(Field, ''));然后工作。太感谢了。你是英雄。
  • @Nevermore 在添加字符串字段时无需手动创建TJSONPair,因为TJSONObject.AddPair() 有一个需要2 个strings 作为输入的重载。
  • 我正在使用 DbXJSon,如果我尝试不创建 TJSONPair,它不会。此外,我使用 Get(Index),Items 对我不起作用。我使用 Size 而不是 Array.Count 可能是我不知道的原因是 DbxJson。我正在使用 XE5。但就目前而言,它正在起作用,我很难相信它。真的真的很感谢你。我快哭了。我以为我永远不会工作。
  • @Nevermore 这是属于您的问题的相关信息。细节很重要。无论如何,相同的AddPair() 重载存在于XE5 中。虽然TJSONArray.Items 失踪你是对的,所以我调整了我的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-11
  • 2019-01-23
  • 2013-08-16
  • 1970-01-01
  • 2016-08-21
  • 2012-07-17
相关资源
最近更新 更多