1
0

rjson.pas 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842
  1. {
  2. TRJSON - JSON Simple Read and Write
  3. - v0.9.7
  4. - 2024-09-14 by gale
  5. - https://github.com/higale/RJSON
  6. }
  7. unit rjson;
  8. interface
  9. uses
  10. System.IOUtils, System.Classes, System.SysUtils, System.JSON, System.Generics.Collections;
  11. type
  12. TJObject = TJSONObject;
  13. TJArray = TJSONArray;
  14. TJValue = TJSONValue;
  15. TJString = TJSONString;
  16. TJNumber = TJSONNumber;
  17. TJBool = TJSONBool;
  18. TJTrue = TJSONTrue;
  19. TJFalse = TJSONFalse;
  20. TJNull = TJSONNull;
  21. TJVType = type of TJValue;
  22. IRJRoot = interface
  23. ['{486F1FA6-2CDD-4124-98C5-CE7C398B7143}']
  24. function GetData: TJValue;
  25. procedure SetData(const AValue: TJValue);
  26. function ForceData(AType: TJVType): TJValue;
  27. property Data: TJValue read GetData write SetData;
  28. end;
  29. TRJSONRoot = class(TInterfacedObject, IRJRoot)
  30. private
  31. FData: TJValue;
  32. function GetData: TJValue;
  33. procedure SetData(const AValue: TJValue);
  34. function ForceData(AType: TJVType): TJValue;
  35. public
  36. constructor Create;
  37. destructor Destroy; override;
  38. end;
  39. TRPath = record
  40. private
  41. FData: string;
  42. public
  43. class operator Implicit(const Value: string): TRPath;
  44. class operator Implicit(Value: Integer): TRPath;
  45. class operator Implicit(const [ref] Value: TRPath): string;
  46. end;
  47. TRJSONEnumerator = class;
  48. TRJSON = record
  49. private
  50. FIRoot: IRJRoot;
  51. FPath: string;
  52. function GetRootRefCount: Integer;
  53. function ForceRootJValue(const APath: string): TJValue;
  54. function LinkPath(const ALeft, ARight: string): string;
  55. function GetJValue: TJValue; inline;
  56. function GetItems(const APath: TRPath): TRJSON;
  57. function GetPairs(AIndex: Integer): TRJSON;
  58. procedure SetValue(const [ref] AValue: TRJSON);
  59. procedure SetItems(const APath: TRPath; const [ref] AValue: TRJSON);
  60. function GetS(const APath: TRPath): string; overload;
  61. procedure SetS(const APath: TRPath; AValue: string); overload;
  62. function GetI(const APath: TRPath): Integer; overload;
  63. procedure SetI(const APath: TRPath; AValue: Integer); overload;
  64. function GetI64(const APath: TRPath): Int64; overload;
  65. procedure SetI64(const APath: TRPath; AValue: Int64); overload;
  66. function GetF(const APath: TRPath): Extended; overload;
  67. procedure SetF(const APath: TRPath; AValue: Extended); overload;
  68. function GetB(const APath: TRPath): Boolean; overload;
  69. procedure SetB(const APath: TRPath; AValue: Boolean); overload;
  70. function GetCount: Integer;
  71. function GetIndex: Integer;
  72. function GetKey: string;
  73. function GetRoot: TRJSON;
  74. public
  75. function GetEnumerator(): TRJSONEnumerator;
  76. class operator Initialize(out Dest: TRJSON);
  77. class operator Finalize(var Dest: TRJSON);
  78. class operator Assign(var Dest: TRJSON; const [ref] Src: TRJSON);
  79. class operator Implicit(const Value: string): TRJSON;
  80. class operator Implicit(const [ref] Value: TRJSON): string;
  81. class operator Implicit(Value: Integer): TRJSON;
  82. class operator Implicit(const [ref] Value: TRJSON): Integer;
  83. class operator Implicit(Value: Int64): TRJSON;
  84. class operator Implicit(const [ref] Value: TRJSON): Int64;
  85. class operator Implicit(Value: Extended): TRJSON;
  86. class operator Implicit(const [ref] Value: TRJSON): Extended;
  87. class operator Implicit(Value: Boolean): TRJSON;
  88. class operator Implicit(const [ref] Value: TRJSON): Boolean;
  89. class operator Implicit(const Value: TJValue): TRJSON;
  90. class operator Implicit(const [ref] Value: TRJSON): TJValue;
  91. function ToStr(const ADefault: string = ''): string;
  92. function ToInt(ADefault: Integer = 0): Integer;
  93. function ToInt64(ADefault: Int64 = 0): Int64;
  94. function ToFloat(ADefault: Extended = 0.0): Extended;
  95. function ToBool(ADefault: Boolean = False): Boolean;
  96. property Items[const APath: TRPath]: TRJSON read GetItems write SetItems; default;
  97. property S[const APath: TRPath]: string read GetS write SetS;
  98. property I[const APath: TRPath]: Integer read GetI write SetI;
  99. property I64[const APath: TRPath]: Int64 read GetI64 write SetI64;
  100. property F[const APath: TRPath]: Extended read GetF write SetF;
  101. property B[const APath: TRPath]: Boolean read GetB write SetB;
  102. property Pairs[AIndex: Integer]: TRJSON read GetPairs;
  103. property Count: Integer read GetCount;
  104. property Index: Integer read GetIndex;
  105. property Key: string read GetKey;
  106. property RootRefCount: Integer read GetRootRefCount;
  107. property Root: TRJSON read GetRoot;
  108. property Path: string read FPath;
  109. property JValue: TJValue read GetJValue;
  110. function CloneJValue: TJValue;
  111. function IsRoot: Boolean; inline;
  112. function RootIsJObject: Boolean; inline;
  113. function RootIsJArray: Boolean; inline;
  114. function IsJObject: Boolean;
  115. function IsJArray: Boolean;
  116. function IsJString: Boolean;
  117. function IsJNumber: Boolean;
  118. function IsJBool: Boolean;
  119. function IsJNull: Boolean;
  120. function IsNil: Boolean;
  121. procedure Reset;
  122. function ToString: string;
  123. function ToJSON(AEncodeBelow32: Boolean = true; AEncodeAbove127: Boolean = true): string;
  124. function Format(AIndentation: Integer = 4): string;
  125. function ParseJValue(const AData: string; AUseBool: Boolean = False; ARaiseExc: Boolean = False): Boolean;
  126. function LoadFromFile(const AFileName: string; AUseBool: Boolean = False; ARaiseExc: Boolean = False): Boolean;
  127. procedure SaveToFile(const AFileName: string; AIndentation: Integer; AWriteBOM: Boolean = False); overload;
  128. procedure SaveToFile(const AFileName: string; AEncodeBelow32: Boolean = true; AEncodeAbove127: Boolean = true; AWriteBOM: Boolean = False); overload;
  129. end;
  130. { Iterators }
  131. TRJSONEnumerator = class
  132. private
  133. FPData: ^TRJSON;
  134. FIndex: Integer;
  135. function GetCurrent: TRJSON;
  136. public
  137. constructor Create(const [ref] AData: TRJSON);
  138. function MoveNext: Boolean;
  139. property Current: TRJSON read GetCurrent;
  140. end;
  141. implementation
  142. { ============================================================================ }
  143. { TRJSONRoot }
  144. constructor TRJSONRoot.Create;
  145. begin
  146. inherited;
  147. FData := nil;
  148. end;
  149. destructor TRJSONRoot.Destroy;
  150. begin
  151. FData.Free;
  152. inherited;
  153. end;
  154. function TRJSONRoot.GetData: TJValue;
  155. begin
  156. Result := FData;
  157. end;
  158. procedure TRJSONRoot.SetData(const AValue: TJValue);
  159. begin
  160. FData := AValue;
  161. end;
  162. function TRJSONRoot.ForceData(AType: TJVType): TJValue;
  163. begin
  164. if not(FData is AType) then
  165. begin
  166. FData.Free;
  167. FData := AType.Create;
  168. end;
  169. Result := FData;
  170. end;
  171. { TRJSONRoot }
  172. { ============================================================================ }
  173. { TJValueHelper }
  174. type
  175. TJValueHelper = class helper for TJValue
  176. private
  177. procedure ObjSetItem(const AName: string; const AValue: TJValue);
  178. procedure ArrFill<T: TJValue>(ACount: Integer);
  179. procedure ArrInsert(const AIndex: Integer; const AValue: TJValue);
  180. procedure ArrSetItem(AIndex: Integer; const AValue: TJValue);
  181. function ToType<T>(ADefault: T): T;
  182. function GetOrCreate<T: TJValue>(AName: string): T;
  183. procedure SetValue(const APath: string; const AValue: TJValue);
  184. procedure TrySetValue(const APath: string; const AValue: TJValue);
  185. end;
  186. procedure TJValueHelper.ObjSetItem(const AName: string; const AValue: TJValue);
  187. var
  188. pairTmp: TJSONPair;
  189. begin
  190. pairTmp := TJObject(self).Get(AName);
  191. if pairTmp = nil then
  192. TJObject(self).AddPair(AName, AValue)
  193. else
  194. pairTmp.JSONValue := AValue;
  195. end;
  196. procedure TJValueHelper.ArrFill<T>(ACount: Integer);
  197. begin
  198. for var j := TJArray(self).Count to ACount do
  199. TJArray(self).AddElement(T.Create);
  200. end;
  201. procedure TJValueHelper.ArrInsert(const AIndex: Integer; const AValue: TJValue);
  202. begin
  203. TJArray(self).AddElement(AValue);
  204. for var I := AIndex to TJArray(self).Count - 2 do
  205. TJArray(self).AddElement(TJArray(self).Remove(AIndex));
  206. end;
  207. procedure TJValueHelper.ArrSetItem(AIndex: Integer; const AValue: TJValue);
  208. begin
  209. ArrFill<TJNull>(AIndex - 1);
  210. if AIndex <= TJArray(self).Count - 1 then
  211. TJArray(self).Remove(AIndex).Free;
  212. ArrInsert(AIndex, AValue);
  213. end;
  214. procedure TJValueHelper.SetValue(const APath: string; const AValue: TJValue);
  215. var
  216. LParser: TJSONPathParser;
  217. preName: string;
  218. jv: TJValue;
  219. begin
  220. if APath.IsEmpty then
  221. raise Exception.Create('TJValueHelper.SetValue: path cannot be empty');
  222. jv := self;
  223. LParser := TJSONPathParser.Create(APath);
  224. LParser.NextToken;
  225. while true do
  226. begin
  227. preName := LParser.TokenName;
  228. LParser.NextToken;
  229. case LParser.Token of
  230. TJSONPathParser.TToken.Name:
  231. jv := jv.GetOrCreate<TJObject>(preName);
  232. TJSONPathParser.TToken.ArrayIndex:
  233. jv := jv.GetOrCreate<TJArray>(preName);
  234. TJSONPathParser.TToken.Eof:
  235. begin
  236. if jv is TJObject then
  237. jv.ObjSetItem(preName, AValue)
  238. else
  239. jv.ArrSetItem(preName.ToInteger, AValue);
  240. break;
  241. end;
  242. else
  243. raise Exception.Create('TJValueHelper.SetValue, LParser.Token Error!');
  244. end;
  245. end;
  246. end;
  247. procedure TJValueHelper.TrySetValue(const APath: string; const AValue: TJValue);
  248. begin
  249. try
  250. SetValue(APath, AValue);
  251. except
  252. on E: Exception do
  253. begin
  254. AValue.Free;
  255. raise Exception.Create(E.Message);
  256. end;
  257. end;
  258. end;
  259. function TJValueHelper.ToType<T>(ADefault: T): T;
  260. begin
  261. if self = nil then
  262. Exit(ADefault);
  263. try
  264. Result := AsType<T>;
  265. except
  266. Result := ADefault;
  267. end;
  268. end;
  269. function TJValueHelper.GetOrCreate<T>(AName: string): T;
  270. begin
  271. if self is TJObject then
  272. begin
  273. Result := T(TJObject(self).GetValue(AName));
  274. if not(Result is T) then
  275. begin
  276. Result := T.Create;
  277. ObjSetItem(AName, Result);
  278. end;
  279. end
  280. else if self is TJArray then
  281. begin
  282. ArrFill<TJNull>(AName.ToInteger);
  283. Result := T(TJArray(self).Items[AName.ToInteger]);
  284. if not(Result is T) then
  285. begin
  286. Result := T.Create;
  287. ArrSetItem(AName.ToInteger, Result);
  288. end;
  289. end
  290. else
  291. begin
  292. raise Exception.Create('GetOrCreate<T> Error, self must be TJO or TJA');
  293. end;
  294. end;
  295. { TJValueHelper }
  296. { ============================================================================ }
  297. { TRPath }
  298. class operator TRPath.Implicit(const Value: string): TRPath;
  299. begin
  300. Result.FData := Value;
  301. end;
  302. class operator TRPath.Implicit(Value: Integer): TRPath;
  303. begin
  304. Result.FData := '[' + Value.ToString + ']';
  305. end;
  306. class operator TRPath.Implicit(const [ref] Value: TRPath): string;
  307. begin
  308. Result := Value.FData;
  309. end;
  310. { TRPath }
  311. { ============================================================================ }
  312. { TRJSONEnumerator }
  313. constructor TRJSONEnumerator.Create(const [ref] AData: TRJSON);
  314. begin
  315. inherited Create;
  316. FPData := @AData;
  317. FIndex := -1;
  318. end;
  319. function TRJSONEnumerator.GetCurrent: TRJSON;
  320. var
  321. jvTmp: TJValue;
  322. begin
  323. Result.Reset;
  324. Result.FIRoot := FPData^.FIRoot;
  325. jvTmp := FPData^.GetJValue;
  326. if jvTmp is TJObject then
  327. begin
  328. if FPData^.FPath = '' then
  329. Result.FPath := TJObject(jvTmp).Pairs[FIndex].JsonString.Value
  330. else
  331. Result.FPath := FPData^.FPath + '.' + TJObject(jvTmp).Pairs[FIndex].JsonString.Value;
  332. end
  333. else if jvTmp is TJArray then
  334. begin
  335. Result.FPath := FPData^.FPath + '[' + FIndex.ToString + ']';
  336. end;
  337. end;
  338. function TRJSONEnumerator.MoveNext: Boolean;
  339. begin
  340. Inc(FIndex);
  341. Exit(FIndex < FPData^.Count)
  342. end;
  343. { TRJSONEnumerator }
  344. { ============================================================================ }
  345. { TRJSON }
  346. function TRJSON.GetEnumerator(): TRJSONEnumerator;
  347. begin
  348. Result := TRJSONEnumerator.Create(self);
  349. end;
  350. class operator TRJSON.Initialize(out Dest: TRJSON);
  351. begin
  352. Dest.FIRoot := TRJSONRoot.Create;
  353. Dest.FPath := '';
  354. end;
  355. class operator TRJSON.Finalize(var Dest: TRJSON);
  356. begin
  357. Dest.FIRoot := nil;
  358. end;
  359. function TRJSON.GetRootRefCount: Integer;
  360. begin
  361. Result := (FIRoot as TRJSONRoot).RefCount;
  362. end;
  363. function TRJSON.ForceRootJValue(const APath: string): TJValue;
  364. begin
  365. if APath.StartsWith('[') then
  366. Result := FIRoot.ForceData(TJArray)
  367. else
  368. Result := FIRoot.ForceData(TJObject);
  369. end;
  370. function TRJSON.LinkPath(const ALeft, ARight: string): string;
  371. begin
  372. if ALeft.IsEmpty then
  373. Result := ARight
  374. else if ARight.IsEmpty then
  375. Result := ALeft
  376. else if ARight.StartsWith('[') then
  377. Result := ALeft + ARight
  378. else
  379. Result := ALeft + '.' + ARight;
  380. end;
  381. function TRJSON.GetJValue: TJValue;
  382. begin
  383. Result := FIRoot.Data.FindValue(FPath);
  384. end;
  385. function TRJSON.CloneJValue: TJValue;
  386. begin
  387. Result := GetJValue;
  388. if Result <> nil then
  389. Result := Result.Clone as TJValue
  390. else
  391. Result := TJNull.Create;
  392. end;
  393. class operator TRJSON.Assign(var Dest: TRJSON; const [ref] Src: TRJSON);
  394. begin
  395. if Dest.FPath.IsEmpty then
  396. begin
  397. Dest.FIRoot := Src.FIRoot;
  398. Dest.FPath := Src.FPath;
  399. end
  400. else
  401. begin
  402. Dest.SetValue(Src);
  403. end;
  404. end;
  405. class operator TRJSON.Implicit(const Value: string): TRJSON;
  406. begin
  407. Result.FIRoot.Data := TJString.Create(Value);
  408. end;
  409. class operator TRJSON.Implicit(const [ref] Value: TRJSON): string;
  410. begin
  411. Result := Value.ToStr('');
  412. end;
  413. class operator TRJSON.Implicit(Value: Integer): TRJSON;
  414. begin
  415. Result.FIRoot.Data := TJNumber.Create(Value);
  416. end;
  417. class operator TRJSON.Implicit(const [ref] Value: TRJSON): Integer;
  418. begin
  419. Result := Value.ToInt(0);
  420. end;
  421. class operator TRJSON.Implicit(Value: Int64): TRJSON;
  422. begin
  423. Result.FIRoot.Data := TJNumber.Create(Value);
  424. end;
  425. class operator TRJSON.Implicit(const [ref] Value: TRJSON): Int64;
  426. begin
  427. Result := Value.ToInt64(0);
  428. end;
  429. class operator TRJSON.Implicit(Value: Extended): TRJSON;
  430. begin
  431. Result.FIRoot.Data := TJNumber.Create(Value);
  432. end;
  433. class operator TRJSON.Implicit(const [ref] Value: TRJSON): Extended;
  434. begin
  435. Result := Value.ToFloat(0.0);
  436. end;
  437. class operator TRJSON.Implicit(Value: Boolean): TRJSON;
  438. begin
  439. Result.FIRoot.Data := TJBool.Create(Value);
  440. end;
  441. class operator TRJSON.Implicit(const [ref] Value: TRJSON): Boolean;
  442. begin
  443. Result := Value.ToBool(False);
  444. end;
  445. class operator TRJSON.Implicit(const Value: TJValue): TRJSON;
  446. begin
  447. Result.FIRoot.Data := Value;
  448. end;
  449. class operator TRJSON.Implicit(const [ref] Value: TRJSON): TJValue;
  450. begin
  451. Result := Value.GetJValue;
  452. end;
  453. function TRJSON.ToStr(const ADefault: string): string;
  454. begin
  455. Result := FIRoot.Data.FindValue(FPath).ToType<string>(ADefault);
  456. end;
  457. function TRJSON.ToInt(ADefault: Integer = 0): Integer;
  458. begin
  459. Result := FIRoot.Data.FindValue(FPath).ToType<Integer>(ADefault);
  460. end;
  461. function TRJSON.ToInt64(ADefault: Int64 = 0): Int64;
  462. begin
  463. Result := FIRoot.Data.FindValue(FPath).ToType<Int64>(ADefault);
  464. end;
  465. function TRJSON.ToFloat(ADefault: Extended = 0.0): Extended;
  466. begin
  467. Result := FIRoot.Data.FindValue(FPath).ToType<Extended>(ADefault);
  468. end;
  469. function TRJSON.ToBool(ADefault: Boolean = False): Boolean;
  470. begin
  471. Result := FIRoot.Data.FindValue(FPath).ToType<Boolean>(ADefault);
  472. end;
  473. function TRJSON.GetItems(const APath: TRPath): TRJSON;
  474. begin
  475. Result.FIRoot := FIRoot;
  476. Result.FPath := LinkPath(FPath, APath);
  477. end;
  478. function TRJSON.GetPairs(AIndex: Integer): TRJSON;
  479. var
  480. jvTmp: TJValue;
  481. begin
  482. jvTmp := GetJValue;
  483. if (jvTmp is TJObject) then
  484. Result := GetItems(TJObject(jvTmp).Pairs[AIndex].JsonString.Value);
  485. end;
  486. procedure TRJSON.SetValue(const [ref] AValue: TRJSON);
  487. var
  488. LValue: TJValue;
  489. begin
  490. {$IFDEF DEBUG}
  491. if FPath.IsEmpty then
  492. raise Exception.Create(' TRJSON.SetValue: Path is empty');
  493. {$ENDIF}
  494. LValue := AValue.CloneJValue;
  495. try
  496. ForceRootJValue(FPath).SetValue(FPath, LValue);
  497. except
  498. on E: Exception do
  499. begin
  500. LValue.Free;
  501. raise Exception.Create(E.Message);
  502. end;
  503. end;
  504. end;
  505. procedure TRJSON.SetItems(const APath: TRPath; const [ref] AValue: TRJSON);
  506. var
  507. tmp: TRJSON;
  508. begin
  509. tmp.FIRoot := FIRoot;
  510. tmp.FPath := LinkPath(FPath, APath);
  511. tmp.SetValue(AValue)
  512. end;
  513. function TRJSON.GetS(const APath: TRPath): string;
  514. var
  515. LPath: string;
  516. begin
  517. LPath := LinkPath(FPath, APath);
  518. Result := ForceRootJValue(LPath).FindValue(LPath).ToType<string>('');
  519. end;
  520. procedure TRJSON.SetS(const APath: TRPath; AValue: string);
  521. var
  522. LPath: string;
  523. begin
  524. LPath := LinkPath(FPath, APath);
  525. ForceRootJValue(LPath).TrySetValue(LPath, TJString.Create(AValue));
  526. end;
  527. function TRJSON.GetI(const APath: TRPath): Integer;
  528. var
  529. LPath: string;
  530. begin
  531. LPath := LinkPath(FPath, APath);
  532. Result := ForceRootJValue(LPath).FindValue(LPath).ToType<Integer>(0);
  533. end;
  534. procedure TRJSON.SetI(const APath: TRPath; AValue: Integer);
  535. var
  536. LPath: string;
  537. begin
  538. LPath := LinkPath(FPath, APath);
  539. ForceRootJValue(LPath).TrySetValue(LPath, TJNumber.Create(AValue));
  540. end;
  541. function TRJSON.GetI64(const APath: TRPath): Int64;
  542. var
  543. LPath: string;
  544. begin
  545. LPath := LinkPath(FPath, APath);
  546. Result := ForceRootJValue(LPath).FindValue(LPath).ToType<Int64>(0);
  547. end;
  548. procedure TRJSON.SetI64(const APath: TRPath; AValue: Int64);
  549. var
  550. LPath: string;
  551. begin
  552. LPath := LinkPath(FPath, APath);
  553. ForceRootJValue(LPath).TrySetValue(LPath, TJNumber.Create(AValue));
  554. end;
  555. function TRJSON.GetF(const APath: TRPath): Extended;
  556. var
  557. LPath: string;
  558. begin
  559. LPath := LinkPath(FPath, APath);
  560. Result := ForceRootJValue(LPath).FindValue(LPath).ToType<Extended>(0.0);
  561. end;
  562. procedure TRJSON.SetF(const APath: TRPath; AValue: Extended);
  563. var
  564. LPath: string;
  565. begin
  566. LPath := LinkPath(FPath, APath);
  567. ForceRootJValue(LPath).TrySetValue(LPath, TJNumber.Create(AValue));
  568. end;
  569. function TRJSON.GetB(const APath: TRPath): Boolean;
  570. var
  571. LPath: string;
  572. begin
  573. LPath := LinkPath(FPath, APath);
  574. Result := ForceRootJValue(LPath).FindValue(LPath).ToType<Boolean>(False);
  575. end;
  576. procedure TRJSON.SetB(const APath: TRPath; AValue: Boolean);
  577. var
  578. LPath: string;
  579. begin
  580. LPath := LinkPath(FPath, APath);
  581. ForceRootJValue(LPath).TrySetValue(LPath, TJBool.Create(AValue));
  582. end;
  583. function TRJSON.GetCount: Integer;
  584. var
  585. jvTemp: TJValue;
  586. begin
  587. jvTemp := GetJValue;
  588. if jvTemp is TJArray then
  589. Result := TJArray(jvTemp).Count
  590. else if jvTemp is TJObject then
  591. Result := TJObject(jvTemp).Count
  592. else
  593. Result := 0;
  594. end;
  595. function TRJSON.GetIndex: Integer;
  596. var
  597. strTmp: string;
  598. begin
  599. Result := -1;
  600. strTmp := FPath.Substring(FPath.LastIndexOf('[') + 1);
  601. if strTmp.EndsWith(']') then
  602. Result := StrToIntDef(strTmp.TrimRight([']']), -1);
  603. end;
  604. function TRJSON.GetKey: string;
  605. begin
  606. Result := FPath.Substring(FPath.LastIndexOf('.') + 1);
  607. if Result.EndsWith(']') then
  608. Result := '';
  609. end;
  610. function TRJSON.GetRoot: TRJSON;
  611. begin
  612. Result.FIRoot := FIRoot;
  613. // Result.FPath := '';
  614. end;
  615. function TRJSON.IsRoot: Boolean;
  616. begin
  617. Result := FPath.IsEmpty;
  618. end;
  619. function TRJSON.RootIsJObject: Boolean;
  620. begin
  621. Result := FIRoot.Data is TJObject;
  622. end;
  623. function TRJSON.RootIsJArray: Boolean;
  624. begin
  625. Result := FIRoot.Data is TJArray;
  626. end;
  627. function TRJSON.IsJObject: Boolean;
  628. begin
  629. Result := GetJValue is TJObject;
  630. end;
  631. function TRJSON.IsJArray: Boolean;
  632. begin
  633. Result := GetJValue is TJArray;
  634. end;
  635. function TRJSON.IsJString: Boolean;
  636. begin
  637. Result := GetJValue is TJString;
  638. end;
  639. function TRJSON.IsJNumber: Boolean;
  640. begin
  641. Result := GetJValue is TJNumber;
  642. end;
  643. function TRJSON.IsJBool: Boolean;
  644. begin
  645. Result := GetJValue is TJBool;
  646. end;
  647. function TRJSON.IsJNull: Boolean;
  648. begin
  649. Result := GetJValue is TJNull;
  650. end;
  651. function TRJSON.IsNil: Boolean;
  652. begin
  653. Result := GetJValue = nil;
  654. end;
  655. procedure TRJSON.Reset;
  656. begin
  657. FIRoot := TRJSONRoot.Create;
  658. FPath := '';
  659. end;
  660. function TRJSON.ToJSON(AEncodeBelow32: Boolean = true; AEncodeAbove127: Boolean = true): string;
  661. var
  662. LValue: TJValue;
  663. Options: TJSONAncestor.TJSONOutputOptions;
  664. begin
  665. Result := '';
  666. LValue := GetJValue;
  667. if LValue <> nil then
  668. begin
  669. Options := [];
  670. if AEncodeBelow32 then
  671. Include(Options, TJSONAncestor.TJSONOutputOption.EncodeBelow32);
  672. if AEncodeAbove127 then
  673. Include(Options, TJSONAncestor.TJSONOutputOption.EncodeAbove127);
  674. Result := LValue.ToJSON(Options);
  675. end;
  676. end;
  677. function TRJSON.ToString: string;
  678. begin
  679. Result := ToJSON(False, False);
  680. end;
  681. function TRJSON.Format(AIndentation: Integer): string;
  682. var
  683. LValue: TJValue;
  684. begin
  685. Result := '';
  686. LValue := GetJValue;
  687. if LValue <> nil then
  688. Result := LValue.Format(AIndentation)
  689. end;
  690. function TRJSON.ParseJValue(const AData: string; AUseBool: Boolean; ARaiseExc: Boolean): Boolean;
  691. begin
  692. Reset;
  693. FIRoot.Data := TJValue.ParseJSONValue(AData, AUseBool, ARaiseExc);
  694. Result := FIRoot.Data <> nil;
  695. end;
  696. function TRJSON.LoadFromFile(const AFileName: string; AUseBool: Boolean; ARaiseExc: Boolean): Boolean;
  697. begin
  698. Result := False;
  699. Reset;
  700. try
  701. FIRoot.Data := TJValue.ParseJSONValue(TFile.ReadAllText(AFileName, TEncoding.UTF8), AUseBool, ARaiseExc);
  702. Result := FIRoot.Data <> nil;
  703. except
  704. on E: Exception do
  705. begin
  706. if ARaiseExc then
  707. raise Exception.Create(E.Message);
  708. end;
  709. end;
  710. end;
  711. procedure TRJSON.SaveToFile(const AFileName: string; AIndentation: Integer; AWriteBOM: Boolean);
  712. var
  713. strs: TStrings;
  714. begin
  715. strs := TStringList.Create;
  716. try
  717. strs.WriteBOM := AWriteBOM;
  718. strs.Text := Format(AIndentation);
  719. strs.SaveToFile(AFileName, TEncoding.UTF8);
  720. finally
  721. strs.Free;
  722. end;
  723. end;
  724. procedure TRJSON.SaveToFile(const AFileName: string; AEncodeBelow32: Boolean = true; AEncodeAbove127: Boolean = true; AWriteBOM: Boolean = False);
  725. var
  726. strs: TStrings;
  727. begin
  728. strs := TStringList.Create;
  729. try
  730. strs.WriteBOM := AWriteBOM;
  731. strs.Text := ToJSON(AEncodeBelow32, AEncodeAbove127);
  732. strs.SaveToFile(AFileName, TEncoding.UTF8);
  733. finally
  734. strs.Free;
  735. end;
  736. end;
  737. { TRJSON }
  738. { ============================================================================ }
  739. end.