如何在Delphi中使用TJSONIterator 备份多级?
How to back up more than one level using TJSONIterator in Delphi?
我一直在尝试使用 Delphi 10.2.2 中的 TJSONIterator
。简短的问题是 "How do I go up two levels in the Iterator
?"
以下代码说明了我的问题:
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;
显然,我正在解析 JSON 字符串以将数据放入数据库 (PDS
)。当我发出第二个 return 时,我没有达到预期的水平,然后我找不到 v4
。我怀疑我可能需要使用 Rewind
方法,但到目前为止我一直无法找到它的文档。
非常感谢任何帮助。
简答
在 Iterator.Return
个调用之间使用 Iterator.Next
。如果您不想在该级别处理任何内容,请清空。
简单替换这部分代码
if Iterator.Next('rv2') then
PDS['Location'] := Iterator.AsString;
Iterator.Return;
end;
有了这个
if Iterator.Next('rv2') then
PDS['Location'] := Iterator.AsString;
Iterator.Return;
Iterator.Next;
end;
长答案
我不确定这是一个错误还是有意为之,文档也没有任何帮助,但 Return
仅适用于一个级别。如果你看一下实现,你会发现 Return
只会将 reader 移动到第一个结束标记,减少深度,并停留在那里,如果它还不在那里的话。
在这种情况下,Return
的第一次调用移动到r2
的末尾并减少深度,下一次调用将什么都不做,因为它已经在末尾并且not FReader.IsEndToken (FReader.TokenType)
条件不满足。
Iterator.Next('v4')
移动到 v3
的末尾并将深度减小到 1,但还将私有变量 FFinished
设置为 True
,这将导致所有其他调用由于 if FFinished then Exit
开头的条件,Next
不会执行任何操作。重置 FFinish
的唯一方法是使用 Return
或 Rewind
.
这个答案解释了如何实现你想做的事情,但不使用 TJsonReader,它是为 delphi 制作的最差 json 解析器(性能和可用性)之一。 (你可以用这个工具做一个基准:https://svn.code.sf.net/p/alcinoe/code/demos/ALJsonDoc/win32/AljsonDocDemo.exe)
例如使用 Alcinoe (https://github.com/Zeus64/alcinoe) 代码非常简单(但任何其他 json 解析器也可以很好地完成这种工作)
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;
我正在寻找有关如何使用 TJSONIterator
的示例,然后来到这里。由于几乎找不到任何东西,我想我会分享我想出的解决方案:
...
ecDebug: TMemo;
...
uses
System.JSON.Builders,
System.JSON.Readers,
...
procedure TForm1.Button1Click(Sender: TObject);
const
JsonRec = '{"v1":"Main","v2":"1.1","v3":{"id":"X45","mod":1.5,' +
'"r2":{"rv1":"99190","rv2":"TX"}},"v4":"ok","v5":69}';
var
StringReader: TStringReader;
JsonTextReader: TJsonTextReader;
Iterator: TJSONIterator;
begin
JsonTextReader:= nil;
Iterator:= nil;
StringReader:= TStringReader.Create(JsonRec);
try
JsonTextReader:= TJsonTextReader.Create(StringReader);
Iterator:= TJSONIterator.Create(JsonTextReader);
while Iterator.Next do
begin
if Iterator.Key = 'v1' then
ecDebug.Lines.Add(Format('Type = %s', [Iterator.AsString]))
else if Iterator.Key = 'v2' then
ecDebug.Lines.Add(Format('Version = %s', [Iterator.AsString]))
else if Iterator.Key = 'v3' then
begin
Iterator.Recurse;
while Iterator.Next do
begin
if Iterator.Key = 'id' then
ecDebug.Lines.Add(Format('BlackListInfo = %s', [Iterator.AsString]))
else if Iterator.Key = 'mod' then
ecDebug.Lines.Add(Format('Speed = %g', [Iterator.AsDouble]))
else if Iterator.Key = 'r2' then
begin
Iterator.Recurse;
while Iterator.Next do
begin
if Iterator.Key = 'rv1' then
ecDebug.Lines.Add(Format('Serial = %s', [Iterator.AsString]))
else if Iterator.Key = 'rv2' then
ecDebug.Lines.Add(Format('Location = %s', [Iterator.AsString]));
end;
Iterator.Return;
end;
end;
Iterator.Return;
end
else if Iterator.Key = 'v4' then
ecDebug.Lines.Add(Format('CRC = %s', [Iterator.AsString]))
else if Iterator.Key = 'v5' then
ecDebug.Lines.Add(Format('ReportID = %d', [Iterator.AsInteger]));
end;
finally
Iterator.Free;
JsonTextReader.Free;
StringReader.Free;
end;
end;
我相信这就是 TJSONIterator
的使用方式。此代码不依赖于 JSON 元素的顺序。
备忘录中的输出是:
Type = Main
Version = 1.1
BlackListInfo = X45
Speed = 1,5
Serial = 99190
Location = TX
CRC = ok
ReportID = 69
我一直在尝试使用 Delphi 10.2.2 中的 TJSONIterator
。简短的问题是 "How do I go up two levels in the Iterator
?"
以下代码说明了我的问题:
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;
显然,我正在解析 JSON 字符串以将数据放入数据库 (PDS
)。当我发出第二个 return 时,我没有达到预期的水平,然后我找不到 v4
。我怀疑我可能需要使用 Rewind
方法,但到目前为止我一直无法找到它的文档。
非常感谢任何帮助。
简答
在 Iterator.Return
个调用之间使用 Iterator.Next
。如果您不想在该级别处理任何内容,请清空。
简单替换这部分代码
if Iterator.Next('rv2') then
PDS['Location'] := Iterator.AsString;
Iterator.Return;
end;
有了这个
if Iterator.Next('rv2') then
PDS['Location'] := Iterator.AsString;
Iterator.Return;
Iterator.Next;
end;
长答案
我不确定这是一个错误还是有意为之,文档也没有任何帮助,但 Return
仅适用于一个级别。如果你看一下实现,你会发现 Return
只会将 reader 移动到第一个结束标记,减少深度,并停留在那里,如果它还不在那里的话。
在这种情况下,Return
的第一次调用移动到r2
的末尾并减少深度,下一次调用将什么都不做,因为它已经在末尾并且not FReader.IsEndToken (FReader.TokenType)
条件不满足。
Iterator.Next('v4')
移动到 v3
的末尾并将深度减小到 1,但还将私有变量 FFinished
设置为 True
,这将导致所有其他调用由于 if FFinished then Exit
开头的条件,Next
不会执行任何操作。重置 FFinish
的唯一方法是使用 Return
或 Rewind
.
这个答案解释了如何实现你想做的事情,但不使用 TJsonReader,它是为 delphi 制作的最差 json 解析器(性能和可用性)之一。 (你可以用这个工具做一个基准:https://svn.code.sf.net/p/alcinoe/code/demos/ALJsonDoc/win32/AljsonDocDemo.exe)
例如使用 Alcinoe (https://github.com/Zeus64/alcinoe) 代码非常简单(但任何其他 json 解析器也可以很好地完成这种工作)
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;
我正在寻找有关如何使用 TJSONIterator
的示例,然后来到这里。由于几乎找不到任何东西,我想我会分享我想出的解决方案:
...
ecDebug: TMemo;
...
uses
System.JSON.Builders,
System.JSON.Readers,
...
procedure TForm1.Button1Click(Sender: TObject);
const
JsonRec = '{"v1":"Main","v2":"1.1","v3":{"id":"X45","mod":1.5,' +
'"r2":{"rv1":"99190","rv2":"TX"}},"v4":"ok","v5":69}';
var
StringReader: TStringReader;
JsonTextReader: TJsonTextReader;
Iterator: TJSONIterator;
begin
JsonTextReader:= nil;
Iterator:= nil;
StringReader:= TStringReader.Create(JsonRec);
try
JsonTextReader:= TJsonTextReader.Create(StringReader);
Iterator:= TJSONIterator.Create(JsonTextReader);
while Iterator.Next do
begin
if Iterator.Key = 'v1' then
ecDebug.Lines.Add(Format('Type = %s', [Iterator.AsString]))
else if Iterator.Key = 'v2' then
ecDebug.Lines.Add(Format('Version = %s', [Iterator.AsString]))
else if Iterator.Key = 'v3' then
begin
Iterator.Recurse;
while Iterator.Next do
begin
if Iterator.Key = 'id' then
ecDebug.Lines.Add(Format('BlackListInfo = %s', [Iterator.AsString]))
else if Iterator.Key = 'mod' then
ecDebug.Lines.Add(Format('Speed = %g', [Iterator.AsDouble]))
else if Iterator.Key = 'r2' then
begin
Iterator.Recurse;
while Iterator.Next do
begin
if Iterator.Key = 'rv1' then
ecDebug.Lines.Add(Format('Serial = %s', [Iterator.AsString]))
else if Iterator.Key = 'rv2' then
ecDebug.Lines.Add(Format('Location = %s', [Iterator.AsString]));
end;
Iterator.Return;
end;
end;
Iterator.Return;
end
else if Iterator.Key = 'v4' then
ecDebug.Lines.Add(Format('CRC = %s', [Iterator.AsString]))
else if Iterator.Key = 'v5' then
ecDebug.Lines.Add(Format('ReportID = %d', [Iterator.AsInteger]));
end;
finally
Iterator.Free;
JsonTextReader.Free;
StringReader.Free;
end;
end;
我相信这就是 TJSONIterator
的使用方式。此代码不依赖于 JSON 元素的顺序。
备忘录中的输出是:
Type = Main
Version = 1.1
BlackListInfo = X45
Speed = 1,5
Serial = 99190
Location = TX
CRC = ok
ReportID = 69