如何用TJSONIterator.Next正确填充TListView?解决首项缺失问题
解决TJSONIterator填充TListView时第一项数据缺失的问题
你当前的代码存在几处逻辑错误,导致第一项数据缺失,同时整体解析逻辑混乱,以下是问题分析和修正方案:
问题分析
- 初始化阶段多余的
NObjJSON := LIterator.AsInteger;完全无意义,此时迭代器尚未定位到有效数值,这行代码会干扰迭代器的初始状态。 - 遇到
StartObject/StartArray后立即调用LIterator.Recurse+LIterator.Next,直接跳过了第一个元素的起始标记,导致第一个JSON对象的解析被跳过。 - 错误地将每个JSON键值对作为ListView的单独项,而非将
success数组中的每个完整对象对应一个ListView项,且内部的for循环逻辑完全错误,重复赋值同一个Item。
原始JSON数据
{ "event":"subscribe-status", "status":"ok", "success":[ { "symbol":"EUR/USD", "exchange":"PHYSICAL CURRENCY", "mic_code":"PHYSICAL CURRENCY", "country":"", "type":"Physical Currency" }, { "symbol":"USD/JPY", "exchange":"PHYSICAL CURRENCY", "mic_code":"PHYSICAL CURRENCY", "country":"", "type":"Physical Currency" }, { "symbol":"BTC/USD", "exchange":"Coinbase Pro", "mic_code":"Coinbase Pro", "country":"", "type":"Digital Currency" }, { "symbol":"ETH/BTC", "exchange":"Huobi", "mic_code":"Huobi", "country":"", "type":"Digital Currency" } ], "fails":null }
修正后的代码
var LStringReader: TStreamReader; LJsonTextReader: TJsonTextReader; LIterator: TJSONIterator; oItem: TListViewItem; ObjIndex: Integer; CurrentSymbol, CurrentExchange: string; begin LStringReader := TStreamReader.Create('../../Data.json', TEncoding.UTF8, True); try LJsonTextReader := TJsonTextReader.Create(LStringReader); try LIterator := TJSONIterator.Create(LJsonTextReader); try ListView1.Items.Clear; ListView1.BeginUpdate; try ObjIndex := 0; // 定位到success数组 while LIterator.Next do begin if LIterator.Key = 'success' then begin if LIterator.&Type = TJsonToken.StartArray then begin // 进入success数组 LIterator.Recurse; // 遍历数组中的每个对象 while LIterator.Next do begin if LIterator.&Type = TJsonToken.StartObject then begin Inc(ObjIndex); CurrentSymbol := ''; CurrentExchange := ''; // 进入当前对象,提取字段 LIterator.Recurse; while LIterator.Next do begin if LIterator.Key = 'symbol' then CurrentSymbol := LIterator.AsValue.ToString else if LIterator.Key = 'exchange' then CurrentExchange := LIterator.AsValue.ToString; end; LIterator.Return; // 退出当前对象 // 创建ListView项并赋值 oItem := ListView1.Items.Add; oItem.Text := 'Object #' + ObjIndex.ToString + ' ' + CurrentSymbol; oItem.Detail := 'Exchange: ' + CurrentExchange; end; end; LIterator.Return; // 退出success数组 Break; // 找到success数组后无需继续遍历外层 end; end; end; finally ListView1.EndUpdate; end; finally LIterator.Free; end; finally LJsonTextReader.Free; end; finally LStringReader.Free; end; end;
代码说明
- 先定位到
success数组,避免遍历无关的JSON字段(如event、status) - 逐个遍历数组中的每个对象,为每个对象创建一个ListView项
- 提取对象中的关键字段(如symbol、exchange)整合到Item的Text和Detail中
- 严格控制迭代器的
Recurse和Return,确保每次进入/退出对象/数组的逻辑正确,不会跳过元素
内容的提问来源于stack exchange,提问作者Ody Light
相关产品推荐
相关产品推荐

