Delphi 10.2.2中使用TJSONIterator如何回退两级?迭代器异常求助
解决Delphi 10.2.2中TJSONIterator回退层级的问题
我之前也碰到过类似的坑,TJSONIterator的Return方法看似是回到父级,但实际嵌套处理后,迭代器的内部状态经常会出现不符合预期的情况,导致后续查找字段失败。咱们来一步步拆解问题并给出可行的解决方案:
问题根源
你两次调用Return后,理论上应该回到根层级,但实际无法找到v4的核心原因是:当你在v3内部用Next依次查找id、mod、r2时,迭代器在v3对象内部已经走到了末尾,此时调用Return回到根层级,原迭代器的位置其实停留在v3字段的“结束位置”,而非根层级的起始位置,后续Next('v4')无法从这个位置正确定位到目标字段——这是Delphi早期版本中TJSONIterator的一个常见小问题。
解决方案1:用子迭代器隔离嵌套操作
最稳妥的方式是为每个嵌套对象创建独立的子迭代器,这样原迭代器的位置不会被嵌套操作干扰,处理完嵌套内容后,原迭代器仍能保持在正确的位置继续查找后续字段。修改后的代码如下:
JsonRec := '{"v1":"Main","v2":"1.1","v3":{"id":"X45","mod":1.5,"r2":{"rv1":"99190","rv2":"TX"}},"v4":"ok","v5":69}'; PDS.Open; PDS.Append; StringReader := TStringReader.Create(JsonRec); JsonTextReader := TJsonTextReader.Create(StringReader); Iterator := TJSONIterator.Create(JsonTextReader); Try If Iterator.Next('v1') Then PDS['Type'] := Iterator.AsString; If Iterator.Next('v2') Then PDS['Version'] := Iterator.AsString; If Iterator.Next('v3') Then Begin // 创建子迭代器处理v3内部内容,不影响原迭代器位置 var ChildIterator := TJSONIterator.Create(Iterator.JsonReader); Try ChildIterator.Recurse; If ChildIterator.Next('id') Then PDS['BlackListInfo'] := ChildIterator.AsString; If ChildIterator.Next('mod') Then PDS['Speed'] := ChildIterator.AsDouble; If ChildIterator.Next('r2') Then begin // 为r2创建孙子迭代器,进一步隔离嵌套操作 var GrandChildIterator := TJSONIterator.Create(ChildIterator.JsonReader); Try GrandChildIterator.Recurse; if GrandChildIterator.Next('rv1') then PDS['Serial'] := GrandChildIterator.AsString; if GrandChildIterator.Next('rv2') then PDS['Location'] := GrandChildIterator.AsString; Finally GrandChildIterator.Free; End; End; Finally ChildIterator.Free; End; // 原迭代器仍停留在v3字段的起始位置,Next('v4')可正常找到目标 if Iterator.Next('v4') then PDS['CRC'] := Iterator.AsString; if Iterator.Next('v5') then PDS['ReportID'] := Iterator.AsInteger; PDS.Post; End; Finally // 务必释放资源,避免内存泄漏 Iterator.Free; JsonTextReader.Free; StringReader.Free; End;
解决方案2:用Rewind重置迭代器到起始位置
如果你不想创建多个子迭代器,可以在两次Return回到根层级后,调用Rewind方法将迭代器重置到JSON的起始位置,再重新查找v4和v5。注意这个方法会让迭代器回到开头,所以不需要重复处理已经完成的v1和v2:
// ... 前面处理v1、v2、v3内部的代码保持不变 ... Iterator.Return; // 回退到v3层级 Iterator.Return; // 回退到根层级 Iterator.Rewind; // 重置迭代器到JSON最开始的位置 // 重新查找v4和v5 if Iterator.Next('v4') then PDS['CRC'] := Iterator.AsString; if Iterator.Next('v5') then PDS['ReportID'] := Iterator.AsInteger; PDS.Post; // ... 后续释放资源的代码 ...
额外小贴士
- 始终用
Try...Finally块包裹迭代器和流对象,这是Delphi中避免内存泄漏的基础操作。 - Delphi 10.2.2的TJSONIterator官方文档确实不够详尽,遇到层级问题时,优先选择子迭代器的方案,它的行为更稳定,不容易出现层级混乱的情况。
内容的提问来源于stack exchange,提问作者SysJames
相关产品推荐
相关产品推荐

