使用TRewindReaderProc重写TJSONIterator类的输入数据

时间:2018-04-04 12:56:35

标签: c++ json c++builder

我正在尝试在使用embarcadero的c ++ builder(Tokyo 10.2 Update 3)构建的程序中解析JSON,考虑到他们严重缺乏文档,这并不容易。

如果您提供的路径(例如TJSONIteratorFind)存在于JSON数据中,我使用[0]['key'] car.model['colour']方法返回true或false embarcadero的文档需要一个传递给TJSONIterator类的构造函数的倒带过程,如果不存在,则会抛出一个异常,说明这一点。

倒带程序应该继承_di_TRewindReaderProc接口,所以这是我的班级。

class rewindclass : public TJSONIterator::_di_TRewindReaderProc
{
    public:
    void __fastcall Invoke(System::Json::Readers::TJsonReader* AReader)
    {
        //code to rewind Iterator
        Areader->Rewind();
    }
};

我不确定应该在Invoke函数中进行什么,因为我说文档没用。显然你必须对传递的TJsonReader做一些事情,我能看到的唯一可以使用的函数是Rewind,但我不认为这是因为文档中关于{的唯一内容{1}}是

TRewindReaderProc

我看不出还有什么可以用来代替。它说必须重置提供输入的实际数据流,但我不知道如何做到这一点。

我正在使用Reference to a procedure that rewinds the input data of the specified JSON reader. Note: TJsonReader.Rewind does not rewind the input data, it resets the state of the JSON reader. This procedure must rewind the actual data stream that provides the input data of the JSON reader. 读取JSON数据,该数据被提供给TStringReader类构造函数,并且被提供给TJsonTextReader类构造函数,其中一个类正在使用TJSONIterator界面。

_di_TRewindReaderProc

这段代码编译好了,但是当我调试它并进入//create rewindclass rewindclass *rewind = new rewindclass(); //setting up TJSONIterator class TStringReader *sread = new TStringReader(this->Memo1->Text); TJsonTextReader *jread = new TJsonTextReader(sread); TJSONIterator *jit = new TJSONIterator(jread, *rewind); 构造函数时,TJSONIterator没有通过,因为当我第二次调用TJsonTextReader方法时抛出异常,表示没有设置回调程序。

所以有人知道为什么没有传递Find以及_di_TRewindReaderProc方法应该采用什么?

2 个答案:

答案 0 :(得分:0)

我在Delphi中遇到了同样的问题几个小时,最后我设法找到一种方法让它工作。我使用TFileStream和TStreamReader作为底层读者而不是TStringReader,但我希望你理解任何读者背后的概念。这是我的代码:

procedure LoadFromFile(AFileName: string);
var
  FS: TFileStream;
  StreamReader: TStreamReader;
  JTReader: TJsonTextReader;
  JIterator: TJSONIterator;

  RewindProc: TJSONIterator.TRewindReaderProc;

begin
  RewindProc := procedure (AReader: TJsonReader)
  begin
    TStreamReader(TJsonTextReader(AReader).Reader).DiscardBufferedData;
    TStreamReader(TJsonTextReader(AReader).Reader).BaseStream.Seek(0, TSeekOrigin.soBeginning);
  end;

  FS:=TFileStream.Create(AFileName, fmOpenRead);
  StreamReader:=TStreamReader.Create(FS);
  JTReader:=TJsonTextReader.Create(StreamReader);
  JIterator:=TJSONIterator.Create(JTReader , RewindProc);

  JIterator.Find('some.path.here');
  JIterator.Find('other.path.here');

end;

RewindProc程序中的线条变得神奇。正如文档所说,你必须对基础读者进行回放,这就是我对这两行所做的。第一个清理StreamReader的内部缓冲区,第二个将文件指针移动到开头。

我希望这会以某种方式帮助您,因为文档非常糟糕,我无法在Internet上找到有关如何正确设置要传递给JSON迭代器的回滚过程的文章。

PD:然后我发现了一些与TIterator.Find一起工作的其他麻烦,但这是另一回事,所以我专注于你的具体问题。

答案 1 :(得分:0)

由于TJSONIterator已经在阅读器上调用了Rewind,因此在调用您的倒带过程之前,无需再次调用倒带。而是重置流并丢弃Reader的所有缓冲区:

procedure TForm1.Button1Click(Sender: TObject);
const
  JsonRec = '{"some":{"path":{"there":"ahi", "here":"acqui"}}}';
var
  StringStream: TStringStream;
  StreamReader: TStreamReader;
  JsonTextReader: TJsonTextReader;
  Iterator: TJSONIterator;
begin
  JsonTextReader:= nil;
  Iterator:= nil;
  StringStream:= TStringStream.Create(JsonRec);
  try
    StreamReader:= TStreamReader.Create(StringStream);
    JsonTextReader:= TJsonTextReader.Create(StreamReader);
    Iterator:= TJSONIterator.Create(JsonTextReader,
      procedure (AReader: TJSONReader)
      var
        v: TValue;
      begin
        StringStream.Seek(0, soBeginning);
        StreamReader.DiscardBufferedData;
        //workaround for RSP-24517
        v:= TRttiContext.Create.GetType(TJsonTextReader).GetField('FChars').GetValue(AReader);
        v.SetArrayElement(0, #0);
      end);
    if Iterator.Find('some.path.here') then
      ecDebug.Lines.Add(Iterator.AsString);
    if Iterator.Find('some.path.there') then
      ecDebug.Lines.Add(Iterator.AsString);
  finally
    Iterator.Free;
    JsonTextReader.Free;
    StreamReader.Free;
    StringStream.Free;
  end;
end;

似乎没有一种重置TStringReader的方法,这就是为什么我使用TStringStream的原因。

更新:我已经在倒带过程中向DiscardBufferedData添加了必要的调用。只有在使用更大的文件进行测试之后,这种情况才会出现。

Update2:对于大于1K的json文件,有一种解决方法,需要解决TJsonTextReader中的错误,该错误无法清除FChar,因此在调用.Rewind导致异常后,它不会重新读取json文件。解析值...时遇到意外字符。”。要访问私有FChar,我正在使用https://stackoverflow.com/a/36717896/386473中所述的RTTI。该错误以https://quality.embarcadero.com/browse/RSP-24517的身份记录在QP中。

相关问题