You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决TJSONIterator与string类型不兼容问题及JSON遍历方法

问题描述

我使用RAD Studio的JSON读写框架(可降低内存消耗),尝试通过HTTP调用RESTful服务获取数据,但出现编译错误:

E2010 Incompatible types: 'TJSONIterator' and 'string'

错误出现在这行代码:

LJRates := LJIter.AsDouble.ToString;

我的代码如下:

Async.Run<TStringList>(function: TStringList
    var
      LHTTP: THTTPClient;
      LResp: IHTTPResponse;
      LJIter: TJSONIterator;
      LJRates: TJSONIterator;
      LJTextR: TJsonTextReader;
      LStrR: TStringReader;
//      LResult: Boolean;
      I: Integer;
    begin
      LHTTP := THTTPClient.Create;
      try
        LResp := LHTTP.Get('http://api.fixer.io/latest');

        {$REGION 'check for errors'}
        if LResp.StatusCode = 200 then
        begin
//          LResult := not LResp.ContentAsString(TEncoding.UTF8).IsEmpty
          // or
//          LStrR := TJSONObject.ParseJSONValue(LResp.ContentAsString(TEncoding.UTF8)) as TJSONObject;
          // or
//        LStrR := LResp.ContentAsString(TEncoding.UTF8);
          // or
          LStrR := TStringReader.Create(LResp.ContentAsString(TEncoding.UTF8));
        end  else
        begin
          raise Exception.CreateFmt('Cannot get rates. HTTP %d - %s', [LResp.StatusCode, LResp.StatusText]);
        end;
        {$ENDREGION}

        LJTextR := TJsonTextReader.Create(LStrR);
        LJIter := TJSONIterator.Create(LJTextR);
        try
          // gets the json object 'rates' and
          LJIter.Recurse; // prepare to enter object
          while LJIter.Next do;
          begin
            LJIter.Recurse; // enter object
            LJIter.Next('rates');
            LJRates := LJIter.AsDouble.ToString;
            Result := TStringList.Create;
            // loop through the property names
            for I := 0 to LJRates.Depth - 1 do
            begin
              //add each names in the resulting TStringList
              Result.Add(LJRates.Path[I]);
            end;
            Result.Sort;
          end;
        finally
          LJIter.Free;
        end;
      finally
        LHTTP.Free;
      end;
    end,

请问正确遍历JSON、读取内容并显示汇率值的方法是什么?

解决方案

错误根源

你声明LJRates为TJSONIterator类型,但代码里试图把LJIter.AsDouble.ToString()的字符串结果赋值给它,类型完全不匹配,这就是编译错误的核心原因。同时你的遍历逻辑也存在问题:比如while LJIter.Next do;后面多了分号,导致后续代码块不会循环执行;定位rates对象的步骤也不正确。

修正后的代码

以下是正确遍历JSON并提取汇率名称与对应数值的代码:

Async.Run<TStringList>(function: TStringList
var
  LHTTP: THTTPClient;
  LResp: IHTTPResponse;
  LJIter: TJSONIterator;
  LJTextR: TJsonTextReader;
  LStrR: TStringReader;
begin
  LHTTP := THTTPClient.Create;
  try
    LResp := LHTTP.Get('http://api.fixer.io/latest');

    if LResp.StatusCode <> 200 then
      raise Exception.CreateFmt('Cannot get rates. HTTP %d - %s', [LResp.StatusCode, LResp.StatusText]);

    LStrR := TStringReader.Create(LResp.ContentAsString(TEncoding.UTF8));
    try
      LJTextR := TJsonTextReader.Create(LStrR);
      try
        LJIter := TJSONIterator.Create(LJTextR);
        try
          Result := TStringList.Create;
          // 定位到JSON根对象
          if LJIter.Next and (LJIter.Kind = TJsonToken.StartObject) then
          begin
            // 进入根对象
            LJIter.Recurse;
            // 查找"rates"字段
            while LJIter.Next do
            begin
              if LJIter.Name = 'rates' then
              begin
                // 进入rates对象
                LJIter.Recurse;
                // 遍历rates下的所有汇率项
                while LJIter.Next do
                begin
                  if LJIter.Kind = TJsonToken.PropertyName then
                  begin
                    // 记录汇率名称
                    var RateName := LJIter.Value.AsString;
                    // 移动到对应的汇率数值节点
                    LJIter.Next;
                    // 将名称和值格式化后添加到结果列表
                    Result.Add(Format('%s: %.4f', [RateName, LJIter.AsDouble]));
                  end;
                end;
                // 退出rates对象
                LJIter.Return;
                break;
              end;
            end;
            // 退出根对象
            LJIter.Return;
          end;
          Result.Sort;
        finally
          LJIter.Free;
        end;
      finally
        LJTextR.Free;
      end;
    finally
      LStrR.Free;
    end;
  finally
    LHTTP.Free;
  end;
end);

关键说明

  1. 资源管理:补充了LStrR和LJTextR的释放操作,避免内存泄漏;
  2. 遍历逻辑优化:
    • 先定位JSON根对象,再精准查找rates字段;
    • 进入rates对象后,遍历每个属性名(汇率名称),再移动到对应的数值节点读取值;
    • 使用Recurse进入对象、Return退出对象,保证迭代器的层级始终正确;
  3. 类型匹配修正:不再混淆迭代器类型与字符串类型,直接读取所需字段值并格式化输出。

内容的提问来源于stack exchange,提问作者LegitLearner

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 10:35:37