jsonparser.pp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. {
  2. This file is part of the Free Component Library
  3. JSON source parser
  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. {$mode objfpc}
  12. {$h+}
  13. unit jsonparser;
  14. interface
  15. uses
  16. Classes, SysUtils, fpJSON, jsonscanner, jsonreader;
  17. Type
  18. { TJSONParser }
  19. TJSONParser = Class(TBaseJSONReader)
  20. private
  21. FStack : Array of TJSONData;
  22. FStackPos : integer;
  23. FStruct : TJSONData;
  24. FValue : TJSONData;
  25. FKey: TJSONStringType;
  26. procedure Pop(aType: TJSONType);
  27. Procedure Push(AValue : TJSONData);
  28. Function NewValue(AValue : TJSONData) : TJSONData;
  29. Protected
  30. Procedure KeyValue(Const AKey : TJSONStringType); override;
  31. Procedure StringValue(Const AValue : TJSONStringType);override;
  32. Procedure NullValue; override;
  33. Procedure FloatValue(Const AValue : Double); override;
  34. Procedure BooleanValue(Const AValue : Boolean); override;
  35. Procedure NumberValue(Const AValue : TJSONStringType); override;
  36. Procedure IntegerValue(Const AValue : integer); override;
  37. Procedure Int64Value(Const AValue : int64); override;
  38. Procedure QWordValue(Const AValue : QWord); override;
  39. Procedure StartArray; override;
  40. Procedure StartObject; override;
  41. Procedure EndArray; override;
  42. Procedure EndObject; override;
  43. Public
  44. function Parse: TJSONData;
  45. end;
  46. EJSONParser = jsonReader.EJSONParser;
  47. implementation
  48. Resourcestring
  49. SErrStructure = 'Structural error';
  50. { TJSONParser }
  51. procedure DefJSONParserHandler(AStream: TStream; const AUseUTF8: Boolean; out
  52. Data: TJSONData);
  53. Var
  54. P : TJSONParser;
  55. AOptions: TJSONOptions;
  56. begin
  57. Data:=Nil;
  58. AOptions:=[];
  59. if AUseUTF8 then
  60. Include(AOptions,joUTF8);
  61. P:=TJSONParser.Create(AStream,AOptions);
  62. try
  63. Data:=P.Parse;
  64. finally
  65. P.Free;
  66. end;
  67. end;
  68. procedure DefJSONStringParserHandler(Const S : TJSONStringType; const AUseUTF8: Boolean; out
  69. Data: TJSONData);
  70. Var
  71. P : TJSONParser;
  72. AOptions: TJSONOptions;
  73. begin
  74. Data:=Nil;
  75. AOptions:=[];
  76. if AUseUTF8 then
  77. Include(AOptions,joUTF8);
  78. P:=TJSONParser.Create(S,AOptions);
  79. try
  80. Data:=P.Parse;
  81. finally
  82. P.Free;
  83. end;
  84. end;
  85. procedure TJSONParser.Pop(aType: TJSONType);
  86. begin
  87. if (FStackPos=0) then
  88. DoError(SErrStructure);
  89. If (FStruct.JSONType<>aType) then
  90. DoError(SErrStructure);
  91. Dec(FStackPos);
  92. FStruct:=FStack[FStackPos];
  93. end;
  94. procedure TJSONParser.Push(AValue: TJSONData);
  95. begin
  96. if (FStackPos=Length(FStack)) then
  97. SetLength(FStack,FStackPos+10);
  98. FStack[FStackPos]:=FStruct;
  99. Inc(FStackPos);
  100. FStruct:=AValue;
  101. end;
  102. function TJSONParser.NewValue(AValue: TJSONData): TJSONData;
  103. begin
  104. Result:=AValue;
  105. // Add to existing structural type
  106. if (FStruct is TJSONObject) then
  107. begin
  108. if (Not (joIgnoreDuplicates in options)) then
  109. try
  110. TJSONObject(FStruct).Add(FKey,AValue);
  111. except
  112. AValue.Free;
  113. Raise;
  114. end
  115. else if (TJSONObject(FStruct).IndexOfName(FKey)=-1) then
  116. TJSONObject(FStruct).Add(FKey,AValue)
  117. else
  118. AValue.Free;
  119. FKey:='';
  120. end
  121. else if (FStruct is TJSONArray) then
  122. TJSONArray(FStruct).Add(AValue);
  123. // The first actual value is our result
  124. if (FValue=Nil) then
  125. FValue:=AValue;
  126. end;
  127. procedure TJSONParser.KeyValue(const AKey: TJSONStringType);
  128. begin
  129. if (FStruct is TJSONObject) and (FKey='') then
  130. FKey:=Akey
  131. else
  132. DoError('Duplicatekey or no object');
  133. end;
  134. procedure TJSONParser.StringValue(const AValue: TJSONStringType);
  135. begin
  136. NewValue(CreateJSON(AValue));
  137. end;
  138. procedure TJSONParser.NullValue;
  139. begin
  140. NewValue(CreateJSON);
  141. end;
  142. procedure TJSONParser.FloatValue(const AValue: Double);
  143. begin
  144. NewValue(CreateJSON(AValue));
  145. end;
  146. procedure TJSONParser.BooleanValue(const AValue: Boolean);
  147. begin
  148. NewValue(CreateJSON(AValue));
  149. end;
  150. procedure TJSONParser.NumberValue(const AValue: TJSONStringType);
  151. begin
  152. // Do nothing
  153. if AValue='' then ;
  154. end;
  155. procedure TJSONParser.IntegerValue(const AValue: integer);
  156. begin
  157. NewValue(CreateJSON(AValue));
  158. end;
  159. procedure TJSONParser.Int64Value(const AValue: int64);
  160. begin
  161. NewValue(CreateJSON(AValue));
  162. end;
  163. procedure TJSONParser.QWordValue(const AValue: QWord);
  164. begin
  165. NewValue(CreateJSON(AValue));
  166. end;
  167. procedure TJSONParser.StartArray;
  168. begin
  169. Push(NewValue(CreateJSONArray([])))
  170. end;
  171. procedure TJSONParser.StartObject;
  172. begin
  173. Push(NewValue(CreateJSONObject([])));
  174. end;
  175. procedure TJSONParser.EndArray;
  176. begin
  177. Pop(jtArray);
  178. end;
  179. procedure TJSONParser.EndObject;
  180. begin
  181. Pop(jtObject);
  182. end;
  183. function TJSONParser.Parse: TJSONData;
  184. begin
  185. SetLength(FStack,0);
  186. FStackPos:=0;
  187. FValue:=Nil;
  188. FStruct:=Nil;
  189. try
  190. DoExecute;
  191. Result:=FValue;
  192. except
  193. On E : exception do
  194. begin
  195. FreeAndNil(FValue);
  196. FStackPos:=0;
  197. SetLength(FStack,0);
  198. Raise;
  199. end;
  200. end;
  201. end;
  202. {
  203. Consume next token and convert to JSON data structure.
  204. If AtCurrent is true, the current token is used. If false,
  205. a token is gotten from the scanner.
  206. If AllowEOF is false, encountering a tkEOF will result in an exception.
  207. }
  208. Procedure InitJSONHandler;
  209. begin
  210. if GetJSONParserHandler=Nil then
  211. SetJSONParserHandler(@DefJSONParserHandler);
  212. if GetJSONStringParserHandler=Nil then
  213. SetJSONStringParserHandler(@DefJSONStringParserHandler);
  214. end;
  215. Procedure DoneJSONHandler;
  216. begin
  217. if GetJSONParserHandler=@DefJSONParserHandler then
  218. SetJSONParserHandler(Nil);
  219. if GetJSONStringParserHandler=@DefJSONStringParserHandler then
  220. SetJSONStringParserHandler(Nil);
  221. end;
  222. initialization
  223. InitJSONHandler;
  224. finalization
  225. DoneJSONHandler;
  226. end.