jsonreader.pp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646
  1. {
  2. This file is part of the Free Component Library
  3. JSON SAX-like Reader
  4. Copyright (c) 2007 by Michael Van Canneyt [email protected]
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {$IFNDEF FPC_DOTTEDUNITS}
  12. unit jsonreader;
  13. {$ENDIF FPC_DOTTEDUNITS}
  14. {$I fcl-json.inc}
  15. interface
  16. {$IFDEF FPC_DOTTEDUNITS}
  17. uses
  18. System.Classes, System.SysUtils, FpJson.Data, FpJson.Scanner;
  19. {$ELSE FPC_DOTTEDUNITS}
  20. uses
  21. Classes, SysUtils, fpJSON, jsonscanner;
  22. {$ENDIF FPC_DOTTEDUNITS}
  23. Type
  24. { TBaseJSONReader }
  25. TBaseJSONReader = Class(TObject)
  26. Private
  27. FScanner : TJSONScanner;
  28. function GetO(AIndex: TJSONOption): Boolean;
  29. function GetOptions: TJSONOptions; inline;
  30. procedure SetO(AIndex: TJSONOption; AValue: Boolean);
  31. procedure SetOptions(AValue: TJSONOptions);
  32. Protected
  33. procedure DoError(const Msg: String);
  34. Procedure DoParse(AtCurrent,AllowEOF: Boolean);
  35. function GetNextToken: TJSONToken;
  36. function CurrentTokenString: RawByteString;
  37. function CurrentToken: TJSONToken; inline;
  38. Procedure KeyValue(Const AKey : TJSONStringType); virtual; abstract;
  39. Procedure StringValue(Const AValue : TJSONStringType);virtual; abstract;
  40. Procedure NullValue; virtual; abstract;
  41. Procedure FloatValue(Const AValue : Double); virtual; abstract;
  42. Procedure BooleanValue(Const AValue : Boolean); virtual; abstract;
  43. Procedure NumberValue(Const AValue : TJSONStringType); virtual; abstract;
  44. Procedure IntegerValue(Const AValue : integer); virtual; abstract;
  45. Procedure Int64Value(Const AValue : int64); virtual; abstract;
  46. Procedure QWordValue(Const AValue : QWord); virtual; abstract;
  47. Procedure StartArray; virtual; abstract;
  48. Procedure StartObject; virtual; abstract;
  49. Procedure EndArray; virtual; abstract;
  50. Procedure EndObject; virtual; abstract;
  51. Procedure ParseArray;
  52. Procedure ParseObject;
  53. Procedure ParseNumber;
  54. Procedure DoExecute;
  55. Property Scanner : TJSONScanner read FScanner;
  56. Public
  57. Constructor Create(Source : TStream; AUseUTF8 : Boolean = True); overload;deprecated 'use options form instead';
  58. Constructor Create(Const Source : RawByteString; AUseUTF8 : Boolean = True); overload;deprecated 'use options form instead';
  59. constructor Create(Source: TStream; AOptions: TJSONOptions); overload;
  60. constructor Create(const Source: RawByteString; AOptions: TJSONOptions); overload;
  61. constructor Create(const Source: UnicodeString; AOptions: TJSONOptions); overload;
  62. destructor Destroy();override;
  63. // Parsing options
  64. Property Options : TJSONOptions Read GetOptions Write SetOptions;
  65. end;
  66. TOnJSONBoolean = Procedure (Sender : TObject; Const AValue : Boolean) of object;
  67. TOnJSONFloat = Procedure (Sender : TObject; Const AValue : TJSONFloat) of object;
  68. TOnJSONInt64 = Procedure (Sender : TObject; Const AValue : Int64) of object;
  69. TOnJSONQWord = Procedure (Sender : TObject; Const AValue : QWord) of object;
  70. TOnJSONInteger = Procedure (Sender : TObject; Const AValue : Integer) of object;
  71. TOnJSONString = Procedure (Sender : TObject; Const AValue : TJSONStringType) of Object;
  72. TOnJSONKey = Procedure (Sender : TObject; Const AKey : TJSONStringType) of Object;
  73. { TJSONEventReader }
  74. TJSONEventReader = Class(TBaseJSONReader)
  75. Private
  76. FOnBooleanValue: TOnJSONBoolean;
  77. FOnEndArray: TNotifyEvent;
  78. FOnEndObject: TNotifyEvent;
  79. FOnFloatValue: TOnJSONFloat;
  80. FOnInt64Value: TOnJSONInt64;
  81. FOnIntegerValue: TOnJSONInteger;
  82. FOnKeyName: TOnJSONKey;
  83. FOnNullValue: TNotifyEvent;
  84. FOnNumberValue: TOnJSONString;
  85. FOnQWordValue: TOnJSONQWord;
  86. FOnStartArray: TNotifyEvent;
  87. FOnStartObject: TNotifyEvent;
  88. FOnStringValue: TOnJSONString;
  89. Protected
  90. Procedure KeyValue(Const AKey : TJSONStringType); override;
  91. Procedure StringValue(Const AValue : TJSONStringType);override;
  92. Procedure NullValue; override;
  93. Procedure FloatValue(Const AValue : Double); override;
  94. Procedure BooleanValue(Const AValue : Boolean); override;
  95. Procedure NumberValue(Const AValue : TJSONStringType); override;
  96. Procedure IntegerValue(Const AValue : integer); override;
  97. Procedure Int64Value(Const AValue : int64); override;
  98. Procedure QWordValue(Const AValue : QWord); override;
  99. Procedure StartArray; override;
  100. Procedure StartObject; override;
  101. Procedure EndArray; override;
  102. Procedure EndObject; override;
  103. Public
  104. Procedure Execute;
  105. Property OnNullValue : TNotifyEvent Read FOnNullValue Write FOnNullValue;
  106. Property OnBooleanValue : TOnJSONBoolean Read FOnBooleanValue Write FOnBooleanValue;
  107. Property OnNumberValue : TOnJSONString Read FOnNumberValue Write FOnNumberValue;
  108. Property OnFloatValue : TOnJSONFloat Read FOnFloatValue Write FOnFloatValue;
  109. Property OnIntegerValue : TOnJSONInteger Read FOnIntegerValue Write FOnIntegerValue;
  110. Property OnInt64Value : TOnJSONInt64 Read FOnInt64Value Write FOnInt64Value;
  111. Property OnQWordValue : TOnJSONQWord Read FOnQWordValue Write FOnQWordValue;
  112. Property OnStringValue : TOnJSONString Read FOnStringValue Write FOnStringValue;
  113. Property OnKeyName : TOnJSONKey Read FOnKeyName Write FOnKeyName;
  114. Property OnStartObject : TNotifyEvent Read FOnStartObject Write FOnStartObject;
  115. Property OnEndObject : TNotifyEvent Read FOnEndObject Write FOnEndObject;
  116. Property OnStartArray : TNotifyEvent Read FOnStartArray Write FOnStartArray;
  117. Property OnEndArray : TNotifyEvent Read FOnEndArray Write FOnEndArray;
  118. end;
  119. IJSONConsumer = Interface ['{60F9D640-2A69-4AAB-8EE1-0DB6DC614D27}']
  120. Procedure NullValue;
  121. Procedure BooleanValue (const AValue : Boolean);
  122. Procedure NumberValue (const AValue : TJSONStringType);
  123. Procedure FloatValue (const AValue : TJSONFloat);
  124. Procedure Int64Value (const AValue : Int64);
  125. Procedure QWordValue (const AValue : QWord);
  126. Procedure IntegerValue(const AValue : Integer) ;
  127. Procedure StringValue(const AValue : TJSONStringType) ;
  128. Procedure KeyName(const AKey : TJSONStringType);
  129. Procedure StartObject;
  130. Procedure EndObject;
  131. Procedure StartArray;
  132. Procedure EndArray;
  133. end;
  134. { TJSONConsumerReader }
  135. TJSONConsumerReader = Class(TBaseJSONReader)
  136. Private
  137. FConsumer: IJSONConsumer;
  138. Protected
  139. Procedure KeyValue(Const AKey : TJSONStringType); override;
  140. Procedure StringValue(Const AValue : TJSONStringType);override;
  141. Procedure NullValue; override;
  142. Procedure FloatValue(Const AValue : Double); override;
  143. Procedure BooleanValue(Const AValue : Boolean); override;
  144. Procedure NumberValue(Const AValue : TJSONStringType); override;
  145. Procedure IntegerValue(Const AValue : integer); override;
  146. Procedure Int64Value(Const AValue : int64); override;
  147. Procedure QWordValue(Const AValue : QWord); override;
  148. Procedure StartArray; override;
  149. Procedure StartObject; override;
  150. Procedure EndArray; override;
  151. Procedure EndObject; override;
  152. Public
  153. Procedure Execute;
  154. Property Consumer : IJSONConsumer Read FConsumer Write FConsumer;
  155. end;
  156. EJSONParser = Class(EParserError);
  157. implementation
  158. Resourcestring
  159. SErrUnexpectedEOF = 'Unexpected EOF encountered.';
  160. SErrUnexpectedToken = 'Unexpected token (%s) encountered.';
  161. SErrExpectedColon = 'Expected colon (:), got token "%s".';
  162. //SErrEmptyElement = 'Empty element encountered.';
  163. SErrExpectedElementName = 'Expected element name, got token "%s"';
  164. SExpectedCommaorBraceClose = 'Expected comma (,) or square bracket (]), got token "%s".';
  165. SErrInvalidNumber = 'Number is not an integer or real number: %s';
  166. SErrNoScanner = 'No scanner. No source specified ?';
  167. SErrorAt = 'Error at line %d, Pos %d: ';
  168. SErrGarbageFound = 'Expected EOF, but got %s';
  169. { TBaseJSONReader }
  170. procedure TBaseJSONReader.DoExecute;
  171. begin
  172. if (FScanner=Nil) then
  173. DoError(SErrNoScanner);
  174. DoParse(False,True);
  175. if joStrict in Options then
  176. begin
  177. Repeat
  178. GetNextToken;
  179. Until CurrentToken<>tkWhiteSpace;
  180. If CurrentToken<>tkEOF then
  181. DoError(Format(SErrGarbageFound,[CurrentTokenString]));
  182. end;
  183. end;
  184. {
  185. Consume next token and convert to JSON data structure.
  186. If AtCurrent is true, the current token is used. If false,
  187. a token is gotten from the scanner.
  188. If AllowEOF is false, encountering a tkEOF will result in an exception.
  189. }
  190. function TBaseJSONReader.CurrentToken: TJSONToken;
  191. begin
  192. Result:=FScanner.CurToken;
  193. end;
  194. function TBaseJSONReader.CurrentTokenString: RawByteString;
  195. begin
  196. If CurrentToken in [tkString,tkIdentifier,tkNumber,tkComment] then
  197. Result:=FScanner.CurTokenString
  198. else
  199. Result:=TokenInfos[CurrentToken];
  200. end;
  201. procedure TBaseJSONReader.DoParse(AtCurrent, AllowEOF: Boolean);
  202. var
  203. T : TJSONToken;
  204. begin
  205. If not AtCurrent then
  206. T:=GetNextToken
  207. else
  208. T:=FScanner.CurToken;
  209. Case T of
  210. tkEof : If Not AllowEof then
  211. DoError(SErrUnexpectedEOF);
  212. tkNull : NullValue;
  213. tkTrue,
  214. tkFalse : BooleanValue(t=tkTrue);
  215. tkString : if (joUTF8 in Options) and (DefaultSystemCodePage<>CP_UTF8) then
  216. StringValue(TJSONStringType(UTF8Decode(CurrentTokenString)))
  217. else
  218. StringValue(CurrentTokenString);
  219. tkCurlyBraceOpen :
  220. ParseObject;
  221. tkCurlyBraceClose :
  222. DoError(SErrUnexpectedToken);
  223. tkSQuaredBraceOpen :
  224. ParseArray;
  225. tkSQuaredBraceClose :
  226. DoError(SErrUnexpectedToken);
  227. tkNumber :
  228. ParseNumber;
  229. tkComma :
  230. DoError(SErrUnexpectedToken);
  231. tkIdentifier :
  232. DoError(SErrUnexpectedToken);
  233. else
  234. // Do nothing
  235. end;
  236. end;
  237. // Creates the correct JSON number type, based on the current token.
  238. procedure TBaseJSONReader.ParseNumber;
  239. Var
  240. I : Integer;
  241. I64 : Int64;
  242. QW : QWord;
  243. F : TJSONFloat;
  244. S : String;
  245. begin
  246. S:=CurrentTokenString;
  247. NumberValue(S);
  248. I:=0;
  249. if TryStrToQWord(S,QW) then
  250. begin
  251. if QW>qword(high(Int64)) then
  252. QWordValue(QW)
  253. else
  254. if QW>MaxInt then
  255. begin
  256. I64 := QW;
  257. Int64Value(I64);
  258. end
  259. else
  260. begin
  261. I:=QW;
  262. IntegerValue(I);
  263. end
  264. end
  265. else
  266. begin
  267. If TryStrToInt64(S,I64) then
  268. if (I64>Maxint) or (I64<-MaxInt) then
  269. Int64Value(I64)
  270. Else
  271. begin
  272. I:=I64;
  273. IntegerValue(I);
  274. end
  275. else
  276. begin
  277. I:=0;
  278. Val(S,F,I);
  279. If (I<>0) then
  280. DoError(SErrInvalidNumber);
  281. FloatValue(F);
  282. end;
  283. end;
  284. end;
  285. function TBaseJSONReader.GetO(AIndex: TJSONOption): Boolean;
  286. begin
  287. Result:=AIndex in Options;
  288. end;
  289. function TBaseJSONReader.GetOptions: TJSONOptions;
  290. begin
  291. Result:=FScanner.Options
  292. end;
  293. procedure TBaseJSONReader.SetO(AIndex: TJSONOption; AValue: Boolean);
  294. begin
  295. if aValue then
  296. FScanner.Options:=FScanner.Options+[AINdex]
  297. else
  298. FScanner.Options:=FScanner.Options-[AINdex]
  299. end;
  300. procedure TBaseJSONReader.SetOptions(AValue: TJSONOptions);
  301. begin
  302. FScanner.Options:=AValue;
  303. end;
  304. // Current token is {, on exit current token is }
  305. procedure TBaseJSONReader.ParseObject;
  306. Var
  307. T : TJSONtoken;
  308. LastComma : Boolean;
  309. S : TJSONStringType;
  310. begin
  311. LastComma:=False;
  312. StartObject;
  313. T:=GetNextToken;
  314. While T<>tkCurlyBraceClose do
  315. begin
  316. If (T<>tkString) and (T<>tkIdentifier) then
  317. DoError(SErrExpectedElementName);
  318. S:=CurrentTokenString;
  319. KeyValue(S);
  320. // Writeln(S);
  321. T:=GetNextToken;
  322. If (T<>tkColon) then
  323. DoError(SErrExpectedColon);
  324. DoParse(False,False);
  325. T:=GetNextToken;
  326. If Not (T in [tkComma,tkCurlyBraceClose]) then
  327. DoError(SExpectedCommaorBraceClose);
  328. If T=tkComma then
  329. begin
  330. T:=GetNextToken;
  331. LastComma:=(t=tkCurlyBraceClose);
  332. end;
  333. end;
  334. If LastComma and ((joStrict in Options) or not (joIgnoreTrailingComma in Options)) then // Test for ,} case
  335. DoError(SErrUnExpectedToken);
  336. EndObject;
  337. end;
  338. // Current token is [, on exit current token is ]
  339. procedure TBaseJSONReader.ParseArray;
  340. Var
  341. T : TJSONtoken;
  342. LastComma : Boolean;
  343. S : TJSONOPTions;
  344. begin
  345. StartArray;
  346. LastComma:=False;
  347. Repeat
  348. T:=GetNextToken;
  349. If (T<>tkSquaredBraceClose) then
  350. begin
  351. DoParse(True,False);
  352. T:=GetNextToken;
  353. If Not (T in [tkComma,tkSquaredBraceClose]) then
  354. DoError(SExpectedCommaorBraceClose);
  355. LastComma:=(t=TkComma);
  356. end;
  357. Until (T=tkSquaredBraceClose);
  358. S:=Options;
  359. If LastComma and ((joStrict in S) or not (joIgnoreTrailingComma in S)) then // Test for ,] case
  360. DoError(SErrUnExpectedToken);
  361. EndArray;
  362. end;
  363. // Get next token, discarding whitespace
  364. function TBaseJSONReader.GetNextToken: TJSONToken;
  365. begin
  366. Repeat
  367. Result:=FScanner.FetchToken;
  368. Until (Not (Result in [tkComment,tkWhiteSpace]));
  369. end;
  370. procedure TBaseJSONReader.DoError(const Msg: String);
  371. Var
  372. S : String;
  373. begin
  374. S:=Format(Msg,[CurrentTokenString]);
  375. S:=Format(SErrorAt,[FScanner.CurRow,FSCanner.CurColumn])+S;
  376. Raise EJSONParser.Create(S);
  377. end;
  378. constructor TBaseJSONReader.Create(Source: TStream; AUseUTF8 : Boolean = True);
  379. begin
  380. Inherited Create;
  381. FScanner:=TJSONScanner.Create(Source,[joUTF8]);
  382. if AUseUTF8 then
  383. Options:=Options + [joUTF8];
  384. end;
  385. constructor TBaseJSONReader.Create(const Source: RawByteString; AUseUTF8 : Boolean = True);
  386. begin
  387. Inherited Create;
  388. FScanner:=TJSONScanner.Create(Source,[joUTF8]);
  389. if AUseUTF8 then
  390. Options:=Options + [joUTF8];
  391. end;
  392. constructor TBaseJSONReader.Create(Source: TStream; AOptions: TJSONOptions);
  393. begin
  394. FScanner:=TJSONScanner.Create(Source,AOptions);
  395. end;
  396. constructor TBaseJSONReader.Create(const Source: RawByteString; AOptions: TJSONOptions);
  397. begin
  398. FScanner:=TJSONScanner.Create(Source,AOptions);
  399. end;
  400. constructor TBaseJSONReader.Create(const Source: UnicodeString;
  401. AOptions: TJSONOptions);
  402. begin
  403. Include(aOptions,joUTF8);
  404. Create(UTF8Encode(Source),aOptions);
  405. end;
  406. destructor TBaseJSONReader.Destroy();
  407. begin
  408. FreeAndNil(FScanner);
  409. inherited Destroy();
  410. end;
  411. { TJSONReader }
  412. procedure TJSONEventReader.KeyValue(const AKey: TJSONStringType);
  413. begin
  414. if Assigned(FOnKeyName) then
  415. FOnKeyName(Self,AKey);
  416. end;
  417. procedure TJSONEventReader.StringValue(const AValue: TJSONStringType);
  418. begin
  419. if Assigned(FOnStringValue) then
  420. FOnStringValue(Self,AValue);
  421. end;
  422. procedure TJSONEventReader.NullValue;
  423. begin
  424. if Assigned(FOnNullValue) then
  425. FOnNullValue(Self);
  426. end;
  427. procedure TJSONEventReader.FloatValue(const AValue: Double);
  428. begin
  429. if Assigned(FOnFloatValue) then
  430. FOnFloatValue(Self,AValue);
  431. end;
  432. procedure TJSONEventReader.BooleanValue(const AValue: Boolean);
  433. begin
  434. if Assigned(FOnBooleanValue) then
  435. FOnBooleanValue(Self,AValue);
  436. end;
  437. procedure TJSONEventReader.NumberValue(const AValue: TJSONStringType);
  438. begin
  439. if Assigned(FOnNumberValue) then
  440. FOnNumberValue(Self,AValue);
  441. end;
  442. procedure TJSONEventReader.IntegerValue(const AValue: integer);
  443. begin
  444. if Assigned(FOnIntegerValue) then
  445. FOnIntegerValue(Self,AValue);
  446. end;
  447. procedure TJSONEventReader.Int64Value(const AValue: int64);
  448. begin
  449. if Assigned(FOnInt64Value) then
  450. FOnInt64Value(Self,AValue);
  451. end;
  452. procedure TJSONEventReader.QWordValue(const AValue: QWord);
  453. begin
  454. if Assigned(FOnQWordValue) then
  455. FOnQWordValue(Self,AValue);
  456. end;
  457. procedure TJSONEventReader.StartArray;
  458. begin
  459. If Assigned(FOnStartArray) then
  460. FOnStartArray(Self);
  461. end;
  462. procedure TJSONEventReader.StartObject;
  463. begin
  464. if Assigned(FOnStartObject) then
  465. FOnStartObject(Self);
  466. end;
  467. procedure TJSONEventReader.EndArray;
  468. begin
  469. If Assigned(FOnEndArray) then
  470. FOnEndArray(Self);
  471. end;
  472. procedure TJSONEventReader.EndObject;
  473. begin
  474. If Assigned(FOnEndObject) then
  475. FOnEndObject(Self);
  476. end;
  477. procedure TJSONEventReader.Execute;
  478. begin
  479. DoExecute;
  480. end;
  481. { TJSONConsumerReader }
  482. procedure TJSONConsumerReader.KeyValue(const AKey: TJSONStringType);
  483. begin
  484. If Assigned(FConsumer) then
  485. FConsumer.KeyName(Akey)
  486. end;
  487. procedure TJSONConsumerReader.StringValue(const AValue: TJSONStringType);
  488. begin
  489. If Assigned(FConsumer) then
  490. FConsumer.StringValue(AValue);
  491. end;
  492. procedure TJSONConsumerReader.NullValue;
  493. begin
  494. If Assigned(FConsumer) then
  495. FConsumer.NullValue;
  496. end;
  497. procedure TJSONConsumerReader.FloatValue(const AValue: Double);
  498. begin
  499. If Assigned(FConsumer) then
  500. FConsumer.FloatValue(AValue);
  501. end;
  502. procedure TJSONConsumerReader.BooleanValue(const AValue: Boolean);
  503. begin
  504. If Assigned(FConsumer) then
  505. FConsumer.BooleanValue(AValue);
  506. end;
  507. procedure TJSONConsumerReader.NumberValue(const AValue: TJSONStringType);
  508. begin
  509. If Assigned(FConsumer) then
  510. FConsumer.NumberValue(AValue);
  511. end;
  512. procedure TJSONConsumerReader.IntegerValue(const AValue: integer);
  513. begin
  514. If Assigned(FConsumer) then
  515. FConsumer.IntegerValue(AValue);
  516. end;
  517. procedure TJSONConsumerReader.Int64Value(const AValue: int64);
  518. begin
  519. If Assigned(FConsumer) then
  520. FConsumer.Int64Value(AValue);
  521. end;
  522. procedure TJSONConsumerReader.QWordValue(const AValue: QWord);
  523. begin
  524. If Assigned(FConsumer) then
  525. FConsumer.QWordValue(AValue);
  526. end;
  527. procedure TJSONConsumerReader.StartArray;
  528. begin
  529. if Assigned(FConsumer) then
  530. FConsumer.StartArray;
  531. end;
  532. procedure TJSONConsumerReader.StartObject;
  533. begin
  534. if Assigned(FConsumer) then
  535. FConsumer.StartObject;
  536. end;
  537. procedure TJSONConsumerReader.EndArray;
  538. begin
  539. if Assigned(FConsumer) then
  540. FConsumer.EndArray;
  541. end;
  542. procedure TJSONConsumerReader.EndObject;
  543. begin
  544. if Assigned(FConsumer) then
  545. FConsumer.EndObject;
  546. end;
  547. procedure TJSONConsumerReader.Execute;
  548. begin
  549. DoExecute;
  550. end;
  551. end.