Search code examples
jsondelphidelphi-10.2-tokyo

How to back up more than one level using TJSONIterator in Delphi?


I am stuck in trying to use the TJSONIterator in Delphi 10.2.2. The short question is "How do I go up two levels in the Iterator?"

The following code illustrates my problem:

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);
If Iterator.Next('v1') Then
   PDS['Type'] := Iterator.AsString;
If Iterator.Next('v2') Then
   PDS['Version'] := Iterator.AsString;
If Iterator.Next('v3') Then
   Begin
   Iterator.Recurse;
   If Iterator.Next('id') Then
      PDS['BlackListInfo'] := Iterator.AsString;
   If Iterator.Next('mod') Then
      PDS['Speed'] := Iterator.AsDouble;
   If Iterator.Next('r2') Then
      begin
      Iterator.Recurse;
      if Iterator.Next('rv1') then
         PDS['Serial'] := Iterator.AsString;
      if Iterator.Next('rv2') then
         PDS['Location'] := Iterator.AsString;
      Iterator.Return;
      end;
   Iterator.Return;   //Second Return does not go up a level.
   if Iterator.Next('v4') then // Always fails
      PDS['CRC'] := Iterator.AsString;
   if Iterator.Next('v5') then
      PDS['ReportID'] := Iterator.AsInteger;
   PDS.Post;
   End;

Obviously, I am parsing the JSON string to put the data into the database (PDS). When I issue the second return, I don't go up to the expected level and then I cannot find v4. I suspect that I may need to use the Rewind method, but so far I have been unable to find it's documentation.

Any help is greatly appreciated.


Solution

  • This answer explain how to achieve what you want to do, but without using TJsonReader that is one of the worse json parser (performance and usability) made for delphi. (you can make a benchmark with this tool: https://svn.code.sf.net/p/alcinoe/code/demos/ALJsonDoc/win32/AljsonDocDemo.exe)

    Using for exemple Alcinoe (https://github.com/Zeus64/alcinoe) the code is pretty simple (but any other json parser can also do this kind of job pretty well)

    MyJsonDoc := TalJsonDocumentU.create;
    try
      MyJsonDoc.loadFromJsonString('{"v1":"Main","v2":"1.1","v3":{"id":"X45","mod":1.5,"r2":{"rv1":"99190","rv2":"TX"}},"v4":"ok","v5":69}');
      PDS['Type'] := MyJsonDoc.node.getchildNodeValueText('v1', ''{default});
      PDS['Version'] := MyJsonDoc.node.getchildNodeValueText('v2', ''{default});
      PDS['BlackListInfo'] := MyJsonDoc.node.getchildNodeValueText(['v3', 'id'], ''{default});
      PDS['Speed'] := MyJsonDoc.node.getchildNodeValueFloat(['v3', 'mod'], 0{default});
      PDS['Serial'] := MyJsonDoc.node.getchildNodeValueText(['v3', 'r2', 'rv1'], ''{default});
      PDS['Location'] := MyJsonDoc.node.getchildNodeValueText(['v3', 'r2', 'rv2'], ''{default});
      PDS['CRC'] := MyJsonDoc.node.getchildNodeValueText('v4', ''{default});
      PDS['ReportID'] := MyJsonDoc.node.getchildNodeValueInt32('v5', 0{default});
    finally
      MyJsonDoc.free;
    end;