higale há 1 ano atrás
pai
commit
5309d2d206
7 ficheiros alterados com 677 adições e 1097 exclusões
  1. 131 154
      README.md
  2. 0 174
      README_ja.md
  3. 0 174
      README_ko.md
  4. 152 0
      README_zh.md
  5. 0 174
      README_zh_CN.md
  6. 0 173
      README_zh_TW.md
  7. 394 248
      rjson.pas

+ 131 - 154
README.md

@@ -2,173 +2,150 @@
 - by gale
 - https://github.com/higale/RJSON
 
-**Languages: [English](README.md) | [简体中文](README_zh_CN.md) | [繁體中文](README_zh_TW.md) | [日本語](README_ja.md) | [한국어](README_ko.md)**
+**Languages: [English](README.md) | [中文](README_zh.md)**
 
-## Properties:
-- `Items[Path]` Path-based read/write, works for both Objects and Arrays.
-
-        a['x.y[2].z'] := 5;
-        b['[3].ok'] := false;
-
-- `Items[Index]` Array read/write.
-
-        a[3][1] := 'hello';
+## Type Aliases
+- TJObject = TJSONObject;
+- TJArray = TJSONArray;
+- TJValue = TJSONValue;
+- TJString = TJSONString;
+- TJNumber = TJSONNumber;
+- TJBool = TJSONBool;
+- TJNull = TJSONNull;
 
-- `Pairs[Index]` Retrieving key-value pairs under a JSONObject.
-
-        for var i := 0 to RJ.Count do
-        begin
-            Memo1.Lines.Add(RJ.Pairs[i].Key + '=' + RJ.Pairs[i].Format(0));
-        end;
-
-- `Count` Number of entries in an Object or Array, returns 0 for other types.
-- `Index` Index of the entry in an Array, returns -1 if not an array data.
-- `Key` If it's a key-value pair data, returns the key, otherwise returns an empty string.
-- `Root` Interface to root data.
+## Properties:
+- `Items[Path]` Default property, Reads and writes based on path, applicable to objects and arrays. Path can be a string or integer index.
+- `S[Path]` Reads and writes string values.
+- `I[Path]` Reads and writes integer values.
+- `I64[Path]` Reads and writes 64-bit integer values.
+- `F[Path]` Reads and writes floating-point values using the Extended type.
+- `B[Path]` Reads and writes boolean values.
+- `Pairs[Index]` Retrieves key-value pairs under a JSONObject.
+- `Count` The number of entries in an object or array; returns 0 for other types.
+- `Index` The index of an entry in an array; returns -1 if not array data.
+- `Key` Returns the key if it is key-value pair data; otherwise, returns an empty string.
+- `RootRefCount` Reference count of the root interface, mainly used for debugging.
+- `Root` Root data.
 - `Path` Path of the value.
-- `JSONValue` Contains the `TJSONValue`.
+- `JValue` Contains the JSON object.
 
 ## Methods
-- `ToStr` Converts to a string, defaults to an empty string.
-
-        var str: string;
-
-        str := RJ['title'];
-        str := RJ['title'].ToStr;
-        str := RJ['title'].ToStr('No Title');
-
-- `ToInt` Converts to an integer, defaults to 0.
-
-        var i: integer;
-
-        i := RJ['num'];
-        i := RJ['num'].ToInt;
-        i := RJ['num'].ToInt(-1);
-
-- `ToInt64` Converts to a 64-bit integer, defaults to 0.
-
-        var i64: Int64;
-
-        i64 := RJ['num64'];
-        i64 := RJ['num64'].ToInt64;
-        i64 := RJ['num64'].ToInt64(-1);
-
-- `ToFloat` Converts to a floating-point number (using Extended), defaults to 0.0.
-
-        var f: Extended;
-
-        f := RJ['num'];
-        f := RJ['num'].ToFloat;
-        f := RJ['num'].ToFloat(100.0);
-
-- `ToBool` Converts to Boolean, defaults to False.
-
-        var b: Boolean;
-
-        b := RJ['bool'];
-        b := RJ['bool'].ToBool;
-        b := RJ['bool'].ToBool(True);
-
-- `RootIs<T: TJSONValue>` Checks if the root is of a certain type (TJSONObject, TJSONArray, etc.).
-- `ValueIs<T: TJSONValue>` Checks if the current value is of a certain type (TJSONObject, TJSONArray, etc.).
-- `CloneJSONValue` Clones the current value, generates TJSONNull if the current value does not exist.
+- `ToStr` Converts to a string; defaults to an empty string.
+- `ToInt` Converts to an integer; defaults to 0.
+- `ToInt64` Converts to a 64-bit integer; defaults to 0.
+- `ToFloat` Converts to a floating-point number (using Extended); defaults to 0.0.
+- `ToBool` Converts to a boolean; defaults to False.
+
+- `CloneJValue` Clones the current value; generates TJNull if the current value does not exist.
+- `IsRoot` Checks if it is root data (Path is empty).
+- `RootIsJObject` Checks if the root is a JObject.
+- `RootIsJArray` Checks if the root is a JArray.
+- `IsJObject` Checks if the value is a JObject.
+- `IsJArray` Checks if the value is a JArray.
+- `IsJString` Checks if the value is a JString.
+- `IsJNumber` Checks if the value is a JNumber.
+- `IsJBool` Checks if the value is a JBool.
+- `IsJNull` Checks if the value is a JNull.
+- `IsNil` Checks if the value is nil.
 - `Reset` Resets to factory settings.
-- `Format` Outputs a formatted JSON string.
-
-        str1 := RJ.Format(2); // Indented by 2 spaces (default is 4)
-        str2 := RJ.Format(0); // Compressed format, no indentation, no line breaks
 
+- `ToString` Outputs a JSON string in compact format without encoding.
+- `ToJSON` Outputs a JSON string in compact format, encoding characters less than 32 or greater than 127 based on parameters.
+- `Format` Outputs a formatted JSON string without encoding.
 - `ParseJSONValue` Loads data from a string.
-
-        RJ.ParseJSONValue('{"a":1}');
-
 - `LoadFromFile` Loads data from a file.
+- `SaveToFile` Saves to a file.
 
-        procedure LoadFromFile(
-            const AFileName: string;   // JSON filename
-            AUseBool: boolean = False; // Whether to create TJSONBool type values when encountering true or false in JSON data
-            ARaiseExc: boolean = False // Whether to throw an exception when encountering invalid JSON data
+        // Saves formatted JSON data to a file.
+        procedure SaveToFile(
+            const AFileName: string; // File name.
+            AIndentation: Integer;   // Number of spaces for indentation.
+            AWriteBOM: boolean = False // Whether to write BOM marker; defaults to False.
         );
 
-- `SaveToFile` Saves to a file.
-
+        // Saves encoded JSON data to a file.
         procedure SaveToFile(
-            const AFileName: string;            // Filename
-            AIndentation: Integer = 4;          // Number of indentation spaces, 0: no indentation, no line breaks
-            AWriteBOM: boolean = False;         // Whether to add a BOM marker to the file
-            ATrailingLineBreak: boolean = False // Whether to add an empty line at the end
+            const AFileName: string;
+            AEncodeBelow32: boolean = true; // Whether to encode ASCII characters less than 32; defaults to True.
+            AEncodeAbove127: boolean = true; // Whether to encode ASCII characters greater than 127; defaults to True.
+            AWriteBOM: boolean = False // Whether to write BOM marker; defaults to False.
         );
 
 ## Example:
-    procedure TFormMain.btnTestClick(Sender: TObject);
-    var
-      RJ, RJ1: TRJ;
-      fTemp: Extended;
-    begin
-      RJ['title'] := 'hello world! 你好,世界!';
-      RJ['a.num'] := 1;
-      RJ['a.hah'] := false;
-      RJ['b[2]'] := 505;
-      RJ['b[0]'] := 'first';
-      RJ['good'] := True;
-      RJ1 := RJ['c'];
-      RJ1['c1'] := 1.1;
-      RJ1['c2[2]'] := 2.33;
-      with RJ['x'] do
-      begin
-        items[1] := 100;
-        items[2] := '202';
-      end;
-      with RJ['y'] do
-      begin
-        items['ya'] := 'y1';
-        items['yb'] := -2;
-      end;
-      Memo1.Text := RJ.Format;
-      Memo1.Lines.Add('-----------------------------------------------------------');
-      fTemp := RJ['c.c2[3]'];
-      Memo1.Lines.Add('fTemp:' + fTemp.ToString);
-      fTemp := RJ['c.c3[3]'].ToFloat(-100);
-      Memo1.Lines.Add('fTemp:' + fTemp.ToString);
-      Memo1.Lines.Add(RJ['a.num'].ToStr('a.num not exist'));
-      Memo1.Lines.Add(RJ['none'].ToFloat(-1).ToString);
-      Memo1.Lines.Add(RJ['none.a3'].ToStr('none.a3 not exist'));
-      RJ.SaveToFile('test.json', 0);
-    end;
-
-    procedure TFormMain.btnOpenClick(Sender: TObject);
-    var
-      RJ: TRJ;
-      strTmp: string;
-    begin
-      RJ.LoadFromFile('test.json');
-      Memo1.Text := RJ.Format(8);
-      Memo1.Lines.Add('-----------------------ROOT--------------------------');
-      for var item in RJ do
-      begin
-        strTmp := Format('Index: %d  Key: %s  Value: %s',
-          [item.Index, item.Key, item.Format(0)]);
-        Memo1.Lines.Add(strTmp);
-      end;
-      Memo1.Lines.Add('-----------------------RJ[a]--------------------------');
-      for var item in RJ['a'] do
-      begin
-        strTmp := Format('Index: %d  Key: %s  Value: %s',
-          [item.Index, item.Key, item.Format(0)]);
-        Memo1.Lines.Add(strTmp);
-      end;
-      Memo1.Lines.Add('-----------------------RJ[b]--------------------------');
-      for var item in RJ['b'] do
-      begin
-        strTmp := Format('Index: %d  Key: %s  Value: %s',
-          [item.Index, item.Key, item.Format(0)]);
-        Memo1.Lines.Add(strTmp);
-      end;
-      Memo1.Lines.Add('-----------------------RJ[c]--------------------------');
-      for var i := 0 to RJ['c'].Count - 1 do
-      begin
-        strTmp := Format('Index: %d  Key: %s  Value: %s',
-          [RJ['c'].Pairs[i].Index, RJ['c'].Pairs[i].Key, RJ['c'].Pairs[i].Format(0)]);
-        Memo1.Lines.Add(strTmp);
-      end;
-    end;
+```pascal
+procedure TFormMain.btnTestClick(Sender: TObject);
+var
+  RJ, RJ1: TRJ;
+  fTemp: Extended;
+begin
+  Memo1.Lines.Clear;
+  RJ['title1'] := 'hello world!';
+  RJ.S['title2'] := '世界,你好!';
+  RJ.Items['title3'] := 'Good';
+  RJ['a.num'] := 1;
+  RJ['a.hah'] := false;
+  RJ['b[2]'] := 505;
+  RJ['b[0]'] := 'first';
+  RJ['good'] := True;
+  RJ1 := RJ['c'];
+  RJ1['c1'] := 1.1;
+  RJ1['c2[2]'] := 2.33;
+  with RJ['x'] do
+  begin
+    items[1] := 100;
+    items[2] := '202';
+  end;
+  with RJ['y'] do
+  begin
+    items['ya'] := 'y1';
+    items['yb'] := -2;
+  end;
+  Memo1.Text := RJ.Format;
+  Memo1.Lines.Add('-----------------------------------------------------------');
+  fTemp := RJ['c.c2[3]'];
+  Memo1.Lines.Add('fTemp:' + fTemp.ToString);
+  fTemp := RJ['c.c3[3]'].ToFloat(-100);
+  Memo1.Lines.Add('fTemp:' + fTemp.ToString);
+  Memo1.Lines.Add(RJ['a.num'].ToStr('a.num not exist'));
+  Memo1.Lines.Add(RJ['none'].ToFloat(-1).ToString);
+  Memo1.Lines.Add(RJ['none.a3'].ToStr('none.a3 not exist'));
+  RJ.SaveToFile('test.json', 0);
+end;
+
+procedure TFormMain.btnOpenClick(Sender: TObject);
+var
+  RJ: TRJ;
+  strTmp: string;
+begin
+  RJ.LoadFromFile('test.json');
+  Memo1.Text := RJ.Format(8);
+  Memo1.Lines.Add('-----------------------ROOT--------------------------');
+  for var item in RJ do
+  begin
+    strTmp := Format('Index: %d  Key: %s  Value: %s',
+      [item.Index, item.Key, item.Format(0)]);
+    Memo1.Lines.Add(strTmp);
+  end;
+  Memo1.Lines.Add('-----------------------RJ[a]--------------------------');
+  for var item in RJ['a'] do
+  begin
+    strTmp := Format('Index: %d  Key: %s  Value: %s',
+      [item.Index, item.Key, item.Format(0)]);
+    Memo1.Lines.Add(strTmp);
+  end;
+  Memo1.Lines.Add('-----------------------RJ[b]--------------------------');
+  for var item in RJ['b'] do
+  begin
+    strTmp := Format('Index: %d  Key: %s  Value: %s',
+      [item.Index, item.Key, item.Format(0)]);
+    Memo1.Lines.Add(strTmp);
+  end;
+  Memo1.Lines.Add('-----------------------RJ[c]--------------------------');
+  for var i := 0 to RJ['c'].Count - 1 do
+  begin
+    strTmp := Format('Index: %d  Key: %s  Value: %s',
+      [RJ['c'].Pairs[i].Index, RJ['c'].Pairs[i].Key, RJ['c'].Pairs[i].Format(0)]);
+    Memo1.Lines.Add(strTmp);
+  end;
+end;
+```

+ 0 - 174
README_ja.md

@@ -1,174 +0,0 @@
-# TRJ - JSON Simple Read and Write
-- by gale
-- https://github.com/higale/RJSON
-
-**Languages: [English](README.md) | [简体中文](README_zh_CN.md) | [繁體中文](README_zh_TW.md) | [日本語](README_ja.md) | [한국어](README_ko.md)**
-
-## 属性:
-- `Items[Path]` パスベースの読み書き、オブジェクトと配列の両方に対応。
-
-        a['x.y[2].z'] := 5;
-        b['[3].ok'] := false;
-
-- `Items[Index]` 配列の読み書き。
-
-        a[3][1] := 'hello';
-
-- `Pairs[Index]` JSONObject 下のキー-値ペアの取得。
-
-        for var i := 0 to RJ.Count do
-        begin
-            Memo1.Lines.Add(RJ.Pairs[i].Key + '=' + RJ.Pairs[i].Format(0));
-        end;
-
-- `Count` オブジェクトまたは配列内のエントリ数、他のタイプでは 0 を返す。
-- `Index` 配列内のエントリのインデックス、配列データでない場合は -1 を返す。
-- `Key` キー-値ペアデータの場合、キーを返す。それ以外は空文字列を返す。
-- `Root` ルートデータへのインターフェース。
-- `Path` 値のパス。
-- `JSONValue` `TJSONValue` を含む。
-
-## メソッド
-- `ToStr` 文字列に変換、デフォルトは空文字列。
-
-        var str: string;
-
-        str := RJ['title'];
-        str := RJ['title'].ToStr;
-        str := RJ['title'].ToStr('No Title');
-
-- `ToInt` 整数に変換、デフォルトは 0。
-
-        var i: integer;
-
-        i := RJ['num'];
-        i := RJ['num'].ToInt;
-        i := RJ['num'].ToInt(-1);
-
-- `ToInt64` 64ビット整数に変換、デフォルトは 0。
-
-        var i64: Int64;
-
-        i64 := RJ['num64'];
-        i64 := RJ['num64'].ToInt64;
-        i64 := RJ['num64'].ToInt64(-1);
-
-- `ToFloat` 浮動小数点数に変換(Extendedを使用)、デフォルトは 0.0。
-
-        var f: Extended;
-
-        f := RJ['num'];
-        f := RJ['num'].ToFloat;
-        f := RJ['num'].ToFloat(100.0);
-
-- `ToBool` Booleanに変換、デフォルトは False。
-
-        var b: Boolean;
-
-        b := RJ['bool'];
-        b := RJ['bool'].ToBool;
-        b := RJ['bool'].ToBool(True);
-
-- `RootIs<T: TJSONValue>` ルートが特定のタイプであるかどうかを確認(TJSONObject、TJSONArrayなど)。
-- `ValueIs<T: TJSONValue>` 現在の値が特定のタイプであるかどうかを確認(TJSONObject、TJSONArrayなど)。
-- `CloneJSONValue` 現在の値をクローン、現在の値がない場合 TJSONNull を生成。
-- `Reset` 工場設定に戻す。
-- `Format` 形式化された JSON 文字列を出力。
-
-        str1 := RJ.Format(2); // 2スペースのインデント(デフォルトは 4)
-        str2 := RJ.Format(0); // 圧縮形式、インデントなし、改行なし
-
-- `ParseJSONValue` 文字列からデータをロード。
-
-        RJ.ParseJSONValue('{"a":1}');
-
-- `LoadFromFile` ファイルからデータをロード。
-
-        procedure LoadFromFile(
-            const AFileName: string;   // JSON ファイル名
-            AUseBool: boolean = False; // JSON データで true または false を検出したときに TJSONBool 型の値を作成するかどうか
-            ARaiseExc: boolean = False // 無効な JSON データを検出したときに例外を発生させるかどうか
-        );
-
-- `SaveToFile` ファイルに保存。
-
-        procedure SaveToFile(
-            const AFileName: string;            // ファイル名
-            AIndentation: Integer = 4;          // インデントのスペース数、0: インデントなし、改行なし
-            AWriteBOM: boolean = False;         // ファイルに BOM マーカーを追加するかどうか
-            ATrailingLineBreak: boolean = False // 末尾に空行を追加するかどうか
-        );
-
-## 例:
-    procedure TFormMain.btnTestClick(Sender: TObject);
-    var
-      RJ, RJ1: TRJ;
-      fTemp: Extended;
-    begin
-      RJ['title'] := 'hello world! 你好,世界!';
-      RJ['a.num'] := 1;
-      RJ['a.hah'] := false;
-      RJ['b[2]'] := 505;
-      RJ['b[0]'] := 'first';
-      RJ['good'] := True;
-      RJ1 := RJ['c'];
-      RJ1['c1'] := 1.1;
-      RJ1['c2[2]'] := 2.33;
-      with RJ['x'] do
-      begin
-        items[1] := 100;
-        items[2] := '202';
-      end;
-      with RJ['y'] do
-      begin
-        items['ya'] := 'y1';
-        items['yb'] := -2;
-      end;
-      Memo1.Text := RJ.Format;
-      Memo1.Lines.Add('-----------------------------------------------------------');
-      fTemp := RJ['c.c2[3]'];
-      Memo1.Lines.Add('fTemp:' + fTemp.ToString);
-      fTemp := RJ['c.c3[3]'].ToFloat(-100);
-      Memo1.Lines.Add('fTemp:' + fTemp.ToString);
-      Memo1.Lines.Add(RJ['a.num'].ToStr('a.num not exist'));
-      Memo1.Lines.Add(RJ['none'].ToFloat(-1).ToString);
-      Memo1.Lines.Add(RJ['none.a3'].ToStr('none.a3 not exist'));
-      RJ.SaveToFile('test.json', 0);
-    end;
-
-    procedure TFormMain.btnOpenClick(Sender: TObject);
-    var
-      RJ: TRJ;
-      strTmp: string;
-    begin
-      RJ.LoadFromFile('test.json');
-      Memo1.Text := RJ.Format(8);
-      Memo1.Lines.Add('-----------------------ROOT--------------------------');
-      for var item in RJ do
-      begin
-        strTmp := Format('Index: %d  Key: %s  Value: %s',
-          [item.Index, item.Key, item.Format(0)]);
-        Memo1.Lines.Add(strTmp);
-      end;
-      Memo1.Lines.Add('-----------------------RJ[a]--------------------------');
-      for var item in RJ['a'] do
-      begin
-        strTmp := Format('Index: %d  Key: %s  Value: %s',
-          [item.Index, item.Key, item.Format(0)]);
-        Memo1.Lines.Add(strTmp);
-      end;
-      Memo1.Lines.Add('-----------------------RJ[b]--------------------------');
-      for var item in RJ['b'] do
-      begin
-        strTmp := Format('Index: %d  Key: %s  Value: %s',
-          [item.Index, item.Key, item.Format(0)]);
-        Memo1.Lines.Add(strTmp);
-      end;
-      Memo1.Lines.Add('-----------------------RJ[c]--------------------------');
-      for var i := 0 to RJ['c'].Count - 1 do
-      begin
-        strTmp := Format('Index: %d  Key: %s  Value: %s',
-          [RJ['c'].Pairs[i].Index, RJ['c'].Pairs[i].Key, RJ['c'].Pairs[i].Format(0)]);
-        Memo1.Lines.Add(strTmp);
-      end;
-    end;

+ 0 - 174
README_ko.md

@@ -1,174 +0,0 @@
-# TRJ - JSON Simple Read and Write
-- by gale
-- https://github.com/higale/RJSON
-
-**Languages: [English](README.md) | [简体中文](README_zh_CN.md) | [繁體中文](README_zh_TW.md) | [日本語](README_ja.md) | [한국어](README_ko.md)**
-
-## 속성:
-- `Items[Path]` 경로 기반 읽기/쓰기, 객체와 배열 모두 지원.
-
-        a['x.y[2].z'] := 5;
-        b['[3].ok'] := false;
-
-- `Items[Index]` 배열 읽기/쓰기.
-
-        a[3][1] := 'hello';
-
-- `Pairs[Index]` JSONObject 아래의 키-값 쌍 검색.
-
-        for var i := 0 to RJ.Count do
-        begin
-            Memo1.Lines.Add(RJ.Pairs[i].Key + '=' + RJ.Pairs[i].Format(0));
-        end;
-
-- `Count` 객체 또는 배열 내 항목 수, 다른 유형은 0 반환.
-- `Index` 배열 내 항목의 인덱스, 배열 데이터가 아닌 경우 -1 반환.
-- `Key` 키-값 쌍 데이터일 경우 키 반환, 그렇지 않으면 빈 문자열 반환.
-- `Root` 루트 데이터에 대한 인터페이스.
-- `Path` 값의 경로.
-- `JSONValue` `TJSONValue`를 포함.
-
-## 메서드
-- `ToStr` 문자열로 변환, 기본값은 빈 문자열.
-
-        var str: string;
-
-        str := RJ['title'];
-        str := RJ['title'].ToStr;
-        str := RJ['title'].ToStr('No Title');
-
-- `ToInt` 정수로 변환, 기본값은 0.
-
-        var i: integer;
-
-        i := RJ['num'];
-        i := RJ['num'].ToInt;
-        i := RJ['num'].ToInt(-1);
-
-- `ToInt64` 64비트 정수로 변환, 기본값은 0.
-
-        var i64: Int64;
-
-        i64 := RJ['num64'];
-        i64 := RJ['num64'].ToInt64;
-        i64 := RJ['num64'].ToInt64(-1);
-
-- `ToFloat` 부동 소수점 수로 변환 (Extended 사용), 기본값은 0.0.
-
-        var f: Extended;
-
-        f := RJ['num'];
-        f := RJ['num'].ToFloat;
-        f := RJ['num'].ToFloat(100.0);
-
-- `ToBool` 부울로 변환, 기본값은 False.
-
-        var b: Boolean;
-
-        b := RJ['bool'];
-        b := RJ['bool'].ToBool;
-        b := RJ['bool'].ToBool(True);
-
-- `RootIs<T: TJSONValue>` 루트가 특정 유형인지 확인 (TJSONObject, TJSONArray 등).
-- `ValueIs<T: TJSONValue>` 현재 값이 특정 유형인지 확인 (TJSONObject, TJSONArray 등).
-- `CloneJSONValue` 현재 값을 클론, 현재 값이 없는 경우 TJSONNull 생성.
-- `Reset` 공장 설정으로 초기화.
-- `Format` 형식화된 JSON 문자열 출력.
-
-        str1 := RJ.Format(2); // 2칸 들여쓰기 (기본값은 4칸)
-        str2 := RJ.Format(0); // 압축 형식, 들여쓰기 없음, 줄 바꿈 없음
-
-- `ParseJSONValue` 문자열에서 데이터 로드.
-
-        RJ.ParseJSONValue('{"a":1}');
-
-- `LoadFromFile` 파일에서 데이터 로드.
-
-        procedure LoadFromFile(
-            const AFileName: string;   // JSON 파일 이름
-            AUseBool: boolean = False; // JSON 데이터에서 true 또는 false를 만나면 TJSONBool 타입 값 생성 여부
-            ARaiseExc: boolean = False // 유효하지 않은 JSON 데이터를 만났을 때 예외 발생 여부
-        );
-
-- `SaveToFile` 파일에 저장.
-
-        procedure SaveToFile(
-            const AFileName: string;            // 파일 이름
-            AIndentation: Integer = 4;          // 들여쓰기 칸 수, 0: 들여쓰기 없음, 줄 바꿈 없음
-            AWriteBOM: boolean = False;         // 파일에 BOM 마커 추가 여부
-            ATrailingLineBreak: boolean = False // 마지막에 빈 줄 추가 여부
-        );
-
-## 예제:
-    procedure TFormMain.btnTestClick(Sender: TObject);
-    var
-      RJ, RJ1: TRJ;
-      fTemp: Extended;
-    begin
-      RJ['title'] := 'hello world! 你好,世界!';
-      RJ['a.num'] := 1;
-      RJ['a.hah'] := false;
-      RJ['b[2]'] := 505;
-      RJ['b[0]'] := 'first';
-      RJ['good'] := True;
-      RJ1 := RJ['c'];
-      RJ1['c1'] := 1.1;
-      RJ1['c2[2]'] := 2.33;
-      with RJ['x'] do
-      begin
-        items[1] := 100;
-        items[2] := '202';
-      end;
-      with RJ['y'] do
-      begin
-        items['ya'] := 'y1';
-        items['yb'] := -2;
-      end;
-      Memo1.Text := RJ.Format;
-      Memo1.Lines.Add('-----------------------------------------------------------');
-      fTemp := RJ['c.c2[3]'];
-      Memo1.Lines.Add('fTemp:' + fTemp.ToString);
-      fTemp := RJ['c.c3[3]'].ToFloat(-100);
-      Memo1.Lines.Add('fTemp:' + fTemp.ToString);
-      Memo1.Lines.Add(RJ['a.num'].ToStr('a.num not exist'));
-      Memo1.Lines.Add(RJ['none'].ToFloat(-1).ToString);
-      Memo1.Lines.Add(RJ['none.a3'].ToStr('none.a3 not exist'));
-      RJ.SaveToFile('test.json', 0);
-    end;
-
-    procedure TFormMain.btnOpenClick(Sender: TObject);
-    var
-      RJ: TRJ;
-      strTmp: string;
-    begin
-      RJ.LoadFromFile('test.json');
-      Memo1.Text := RJ.Format(8);
-      Memo1.Lines.Add('-----------------------ROOT--------------------------');
-      for var item in RJ do
-      begin
-        strTmp := Format('Index: %d  Key: %s  Value: %s',
-          [item.Index, item.Key, item.Format(0)]);
-        Memo1.Lines.Add(strTmp);
-      end;
-      Memo1.Lines.Add('-----------------------RJ[a]--------------------------');
-      for var item in RJ['a'] do
-      begin
-        strTmp := Format('Index: %d  Key: %s  Value: %s',
-          [item.Index, item.Key, item.Format(0)]);
-        Memo1.Lines.Add(strTmp);
-      end;
-      Memo1.Lines.Add('-----------------------RJ[b]--------------------------');
-      for var item in RJ['b'] do
-      begin
-        strTmp := Format('Index: %d  Key: %s  Value: %s',
-          [item.Index, item.Key, item.Format(0)]);
-        Memo1.Lines.Add(strTmp);
-      end;
-      Memo1.Lines.Add('-----------------------RJ[c]--------------------------');
-      for var i := 0 to RJ['c'].Count - 1 do
-      begin
-        strTmp := Format('Index: %d  Key: %s  Value: %s',
-          [RJ['c'].Pairs[i].Index, RJ['c'].Pairs[i].Key, RJ['c'].Pairs[i].Format(0)]);
-        Memo1.Lines.Add(strTmp);
-      end;
-    end;

+ 152 - 0
README_zh.md

@@ -0,0 +1,152 @@
+# TRJ - JSON Simple Read and Write
+- by gale
+- https://github.com/higale/RJSON
+
+**Languages: [English](README.md) | [中文](README_zh.md)**
+
+## 类型别名
+- TJObject = TJSONObject;
+- TJArray = TJSONArray;
+- TJValue = TJSONValue;
+- TJString = TJSONString;
+- TJNumber = TJSONNumber;
+- TJBool = TJSONBool;
+- TJNull = TJSONNull;
+
+## 属性:
+- `Items[Path]` 缺省属性,基于路径读写,适用于对象和数组,Path 可以是字符串或整数索引。
+- `S[Path]` 字符串数值读写
+- `I[Path]` 整数数值读写
+- `I64[Path]` 64位整数数值读写
+- `F[Path]` 浮点数数值读写,使用 Extended 类型
+- `B[Path]` 布尔数值读写
+- `Pairs[Index]` 获取 JSONObject 下的键值对。
+- `Count` 对象或数组中的条目数量,其他类型返回 0。
+- `Index` 数组中的条目索引,如果不是数组数据则返回 -1。
+- `Key` 如果是键值对数据,则返回键,否则返回空字符串。
+- `RootRefCount` Root接口引用次数,主要用于调试
+- `Root` 根数据。
+- `Path` 值的路径。
+- `JValue` 包含的JSON对象。
+
+## 方法
+- `ToStr` 转换为字符串,默认为空字符串。
+- `ToInt` 转换为整数,默认为 0。
+- `ToInt64` 转换为 64 位整数,默认为 0。
+- `ToFloat` 转换为浮点数(使用 Extended),默认为 0.0。
+- `ToBool` 转换为布尔值,默认为 False。
+
+- `CloneJValue` 克隆当前值,如果当前值不存在,则生成 TJNull。
+- `IsRoot` 是否是根数据(Path为空)
+- `RootIsJObject` 根是否是JObject
+- `RootIsJArray` 根是否是JArray
+- `IsJObject` 值是否是JObject
+- `IsJArray` 值是否是JObject
+- `IsJString` 值是否是JString
+- `IsJNumber` 值是否是JNumber
+- `IsJBool` 值是否是JBool
+- `IsJNull` 值是否是JJNull
+- `IsNil` 值是否为空
+- `Reset` 重置为出厂设置
+
+- `ToString` 输出 JSON 字符串,紧凑格式,不做编码。
+- `ToJSON` 输出 JSON 字符串,紧凑格式,根据参数对小于32或大于127的字符编码。
+- `Format` 输出格式化的 JSON 字符串,不做编码。
+- `ParseJSONValue` 从字符串加载数据。
+- `LoadFromFile` 从文件加载数据。
+- `SaveToFile` 保存到文件。
+
+        // 将格式化过的JSON数据保存到文件。
+        procedure SaveToFile(
+            const AFileName: string; // 文件名。
+            AIndentation: Integer;   // 缩进的空格数。
+            AWriteBOM: boolean = False // 是否写入BOM标记,默认为False。
+        );
+
+        //以编码过的JSON数据保存到文件。
+        procedure SaveToFile(
+            const AFileName: string;
+            AEncodeBelow32: boolean = true; // 是否编码ASCII码小于32的字符,默认为True。
+            AEncodeAbove127: boolean = true; // 是否编码ASCII码大于127的字符,默认为True。
+            AWriteBOM: boolean = False // 是否写入BOM标记,默认为False。
+        );
+
+
+## 示例:
+```pascal
+procedure TFormMain.btnTestClick(Sender: TObject);
+var
+  RJ, RJ1: TRJ;
+  fTemp: Extended;
+begin
+  Memo1.Lines.Clear;
+  RJ['title1'] := 'hello world!';
+  RJ.S['title2'] := '世界,你好!';
+  RJ.Items['title3'] := 'Good';
+  RJ['a.num'] := 1;
+  RJ['a.hah'] := false;
+  RJ['b[2]'] := 505;
+  RJ['b[0]'] := 'first';
+  RJ['good'] := True;
+  RJ1 := RJ['c'];
+  RJ1['c1'] := 1.1;
+  RJ1['c2[2]'] := 2.33;
+  with RJ['x'] do
+  begin
+    items[1] := 100;
+    items[2] := '202';
+  end;
+  with RJ['y'] do
+  begin
+    items['ya'] := 'y1';
+    items['yb'] := -2;
+  end;
+  Memo1.Text := RJ.Format;
+  Memo1.Lines.Add('-----------------------------------------------------------');
+  fTemp := RJ['c.c2[3]'];
+  Memo1.Lines.Add('fTemp:' + fTemp.ToString);
+  fTemp := RJ['c.c3[3]'].ToFloat(-100);
+  Memo1.Lines.Add('fTemp:' + fTemp.ToString);
+  Memo1.Lines.Add(RJ['a.num'].ToStr('a.num not exist'));
+  Memo1.Lines.Add(RJ['none'].ToFloat(-1).ToString);
+  Memo1.Lines.Add(RJ['none.a3'].ToStr('none.a3 not exist'));
+  RJ.SaveToFile('test.json', 0);
+end;
+
+procedure TFormMain.btnOpenClick(Sender: TObject);
+var
+  RJ: TRJ;
+  strTmp: string;
+begin
+  RJ.LoadFromFile('test.json');
+  Memo1.Text := RJ.Format(8);
+  Memo1.Lines.Add('-----------------------ROOT--------------------------');
+  for var item in RJ do
+  begin
+    strTmp := Format('Index: %d  Key: %s  Value: %s',
+      [item.Index, item.Key, item.Format(0)]);
+    Memo1.Lines.Add(strTmp);
+  end;
+  Memo1.Lines.Add('-----------------------RJ[a]--------------------------');
+  for var item in RJ['a'] do
+  begin
+    strTmp := Format('Index: %d  Key: %s  Value: %s',
+      [item.Index, item.Key, item.Format(0)]);
+    Memo1.Lines.Add(strTmp);
+  end;
+  Memo1.Lines.Add('-----------------------RJ[b]--------------------------');
+  for var item in RJ['b'] do
+  begin
+    strTmp := Format('Index: %d  Key: %s  Value: %s',
+      [item.Index, item.Key, item.Format(0)]);
+    Memo1.Lines.Add(strTmp);
+  end;
+  Memo1.Lines.Add('-----------------------RJ[c]--------------------------');
+  for var i := 0 to RJ['c'].Count - 1 do
+  begin
+    strTmp := Format('Index: %d  Key: %s  Value: %s',
+      [RJ['c'].Pairs[i].Index, RJ['c'].Pairs[i].Key, RJ['c'].Pairs[i].Format(0)]);
+    Memo1.Lines.Add(strTmp);
+  end;
+end;
+```

+ 0 - 174
README_zh_CN.md

@@ -1,174 +0,0 @@
-# TRJ - JSON Simple Read and Write
-- by gale
-- https://github.com/higale/RJSON
-
-**Languages: [English](README.md) | [简体中文](README_zh_CN.md) | [繁體中文](README_zh_TW.md) | [日本語](README_ja.md) | [한국어](README_ko.md)**
-
-## 属性:
-- `Items[Path]` 基于路径的读写,适用于对象和数组。
- 
-        a['x.y[2].z'] := 5;
-        b['[3].ok'] := false;
-
-- `Items[Index]` 数组读写。
-
-        a[3][1] := 'hello';
-
-- `Pairs[Index]` 获取 JSONObject 下的键值对。
-
-        for var i := 0 to RJ.Count do
-        begin
-            Memo1.Lines.Add(RJ.Pairs[i].Key + '=' + RJ.Pairs[i].Format(0));
-        end;
-
-- `Count` 对象或数组中的条目数量,其他类型返回 0。
-- `Index` 数组中的条目索引,如果不是数组数据则返回 -1。
-- `Key` 如果是键值对数据,则返回键,否则返回空字符串。
-- `Root` 根数据接口。
-- `Path` 值的路径。
-- `JSONValue` 包含的 `TJSONValue`。
-
-## 方法
-- `ToStr` 转换为字符串,默认为空字符串。
-
-        var str: string;
-
-        str := RJ['title'];
-        str := RJ['title'].ToStr;
-        str := RJ['title'].ToStr('没有标题');
-
-- `ToInt` 转换为整数,默认为 0。
-
-        var i: integer;
-
-        i := RJ['num'];
-        i := RJ['num'].ToInt;
-        i := RJ['num'].ToInt(-1);
-
-- `ToInt64` 转换为 64 位整数,默认为 0。
-
-        var i64: Int64;
-
-        i64 := RJ['num64'];
-        i64 := RJ['num64'].ToInt64;
-        i64 := RJ['num64'].ToInt64(-1);
-
-- `ToFloat` 转换为浮点数(使用 Extended),默认为 0.0。
-
-        var f: Extended;
-
-        f := RJ['num'];
-        f := RJ['num'].ToFloat;
-        f := RJ['num'].ToFloat(100.0);
-
-- `ToBool` 转换为布尔值,默认为 False。
-
-        var b: Boolean;
-
-        b := RJ['bool'];
-        b := RJ['bool'].ToBool;
-        b := RJ['bool'].ToBool(True);
-
-- `RootIs<T: TJSONValue>` 检查根是否为特定类型(TJSONObject、TJSONArray 等)。
-- `ValueIs<T: TJSONValue>` 检查当前值是否为特定类型(TJSONObject、TJSONArray 等)。
-- `CloneJSONValue` 克隆当前值,如果当前值不存在,则生成 TJSONNull。
-- `Reset` 重置为出厂设置。
-- `Format` 输出格式化的 JSON 字符串。
-
-        str1 := RJ.Format(2); // 缩进 2 个空格(默认为 4)
-        str2 := RJ.Format(0); // 压缩格式,无缩进无换行
-
-- `ParseJSONValue` 从字符串加载数据。
-
-        RJ.ParseJSONValue('{"a":1}');
-
-- `LoadFromFile` 从文件加载数据。
-
-        procedure LoadFromFile(
-            const AFileName: string;   // JSON 文件名
-            AUseBool: boolean = False; // 遇到 JSON 数据中的 true 或 false 时,是否创建 TJSONBool 类型的值
-            ARaiseExc: boolean = False // 遇到无效的 JSON 数据时是否抛出异常
-        );
-
-- `SaveToFile` 保存到文件。
-
-        procedure SaveToFile(
-            const AFileName: string;            // 文件名
-            AIndentation: Integer = 4;          // 缩进空格数,0: 不缩进不换行
-            AWriteBOM: boolean = False;         // 文件是否添加 BOM 标记
-            ATrailingLineBreak: boolean = False // 是否在结尾添加一个空行
-        );
-
-## 示例:
-    procedure TFormMain.btnTestClick(Sender: TObject);
-    var
-      RJ, RJ1: TRJ;
-      fTemp: Extended;
-    begin
-      RJ['title'] := 'hello world! 你好,世界!';
-      RJ['a.num'] := 1;
-      RJ['a.hah'] := false;
-      RJ['b[2]'] := 505;
-      RJ['b[0]'] := 'first';
-      RJ['good'] := True;
-      RJ1 := RJ['c'];
-      RJ1['c1'] := 1.1;
-      RJ1['c2[2]'] := 2.33;
-      with RJ['x'] do
-      begin
-        items[1] := 100;
-        items[2] := '202';
-      end;
-      with RJ['y'] do
-      begin
-        items['ya'] := 'y1';
-        items['yb'] := -2;
-      end;
-      Memo1.Text := RJ.Format;
-      Memo1.Lines.Add('-----------------------------------------------------------');
-      fTemp := RJ['c.c2[3]'];
-      Memo1.Lines.Add('fTemp:' + fTemp.ToString);
-      fTemp := RJ['c.c3[3]'].ToFloat(-100);
-      Memo1.Lines.Add('fTemp:' + fTemp.ToString);
-      Memo1.Lines.Add(RJ['a.num'].ToStr('a.num not exist'));
-      Memo1.Lines.Add(RJ['none'].ToFloat(-1).ToString);
-      Memo1.Lines.Add(RJ['none.a3'].ToStr('none.a3 not exist'));
-      RJ.SaveToFile('test.json', 0);
-    end;
-
-    procedure TFormMain.btnOpenClick(Sender: TObject);
-    var
-      RJ: TRJ;
-      strTmp: string;
-    begin
-      RJ.LoadFromFile('test.json');
-      Memo1.Text := RJ.Format(8);
-      Memo1.Lines.Add('-----------------------ROOT--------------------------');
-      for var item in RJ do
-      begin
-        strTmp := Format('Index: %d  Key: %s  Value: %s',
-          [item.Index, item.Key, item.Format(0)]);
-        Memo1.Lines.Add(strTmp);
-      end;
-      Memo1.Lines.Add('-----------------------RJ[a]--------------------------');
-      for var item in RJ['a'] do
-      begin
-        strTmp := Format('Index: %d  Key: %s  Value: %s',
-          [item.Index, item.Key, item.Format(0)]);
-        Memo1.Lines.Add(strTmp);
-      end;
-      Memo1.Lines.Add('-----------------------RJ[b]--------------------------');
-      for var item in RJ['b'] do
-      begin
-        strTmp := Format('Index: %d  Key: %s  Value: %s',
-          [item.Index, item.Key, item.Format(0)]);
-        Memo1.Lines.Add(strTmp);
-      end;
-      Memo1.Lines.Add('-----------------------RJ[c]--------------------------');
-      for var i := 0 to RJ['c'].Count - 1 do
-      begin
-        strTmp := Format('Index: %d  Key: %s  Value: %s',
-          [RJ['c'].Pairs[i].Index, RJ['c'].Pairs[i].Key, RJ['c'].Pairs[i].Format(0)]);
-        Memo1.Lines.Add(strTmp);
-      end;
-    end;

+ 0 - 173
README_zh_TW.md

@@ -1,173 +0,0 @@
-# TRJ - JSON Simple Read and Write
-- by gale
-- https://github.com/higale/RJSON
-
-**Languages: [English](README.md) | [简体中文](README_zh_CN.md) | [繁體中文](README_zh_TW.md) | [日本語](README_ja.md) | [한국어](README_ko.md)**
-## 屬性:
-- `Items[Path]` 基於路徑的讀寫,適用於物件和陣列。
-
-        a['x.y[2].z'] := 5;
-        b['[3].ok'] := false;
-
-- `Items[Index]` 陣列讀寫。
-
-        a[3][1] := 'hello';
-
-- `Pairs[Index]` 獲取 JSONObject 下的鍵值對。
-
-        for var i := 0 to RJ.Count do
-        begin
-            Memo1.Lines.Add(RJ.Pairs[i].Key + '=' + RJ.Pairs[i].Format(0));
-        end;
-
-- `Count` 物件或陣列中的條目數量,其他類型返回 0。
-- `Index` 陣列中的條目索引,如果不是陣列數據則返回 -1。
-- `Key` 如果是鍵值對數據,則返回鍵,否則返回空字符串。
-- `Root` 根數據接口。
-- `Path` 值的路徑。
-- `JSONValue` 包含的 `TJSONValue`。
-
-## 方法
-- `ToStr` 轉換為字符串,默認為空字符串。
-
-        var str: string;
-
-        str := RJ['title'];
-        str := RJ['title'].ToStr;
-        str := RJ['title'].ToStr('沒有標題');
-
-- `ToInt` 轉換為整數,默認為 0。
-
-        var i: integer;
-
-        i := RJ['num'];
-        i := RJ['num'].ToInt;
-        i := RJ['num'].ToInt(-1);
-
-- `ToInt64` 轉換為 64 位整數,默認為 0。
-
-        var i64: Int64;
-
-        i64 := RJ['num64'];
-        i64 := RJ['num64'].ToInt64;
-        i64 := RJ['num64'].ToInt64(-1);
-
-- `ToFloat` 轉換為浮點數(使用 Extended),默認為 0.0。
-
-        var f: Extended;
-
-        f := RJ['num'];
-        f := RJ['num'].ToFloat;
-        f := RJ['num'].ToFloat(100.0);
-
-- `ToBool` 轉換為布林值,默認為 False。
-
-        var b: Boolean;
-
-        b := RJ['bool'];
-        b := RJ['bool'].ToBool;
-        b := RJ['bool'].ToBool(True);
-
-- `RootIs<T: TJSONValue>` 檢查根是否為特定類型(TJSONObject、TJSONArray 等)。
-- `ValueIs<T: TJSONValue>` 檢查當前值是否為特定類型(TJSONObject、TJSONArray 等)。
-- `CloneJSONValue` 克隆當前值,如果當前值不存在,則生成 TJSONNull。
-- `Reset` 重置為出廠設置。
-- `Format` 輸出格式化的 JSON 字符串。
-
-        str1 := RJ.Format(2); // 縮進 2 個空格(默認為 4)
-        str2 := RJ.Format(0); // 壓縮格式,無縮進無換行
-
-- `ParseJSONValue` 從字符串加載數據。
-
-        RJ.ParseJSONValue('{"a":1}');
-
-- `LoadFromFile` 從文件加載數據。
-
-        procedure LoadFromFile(
-            const AFileName: string;   // JSON 文件名
-            AUseBool: boolean = False; // 遇到 JSON 數據中的 true 或 false 時,是否創建 TJSONBool 類型的值
-            ARaiseExc: boolean = False // 遇到無效的 JSON 數據時是否拋出異常
-        );
-
-- `SaveToFile` 保存到文件。
-
-        procedure SaveToFile(
-            const AFileName: string;            // 文件名
-            AIndentation: Integer = 4;          // 縮進空格數,0: 不縮進不換行
-            AWriteBOM: boolean = False;         // 文件是否添加 BOM 標記
-            ATrailingLineBreak: boolean = False // 是否在結尾添加一個空行
-        );
-
-## 範例:
-    procedure TFormMain.btnTestClick(Sender: TObject);
-    var
-      RJ, RJ1: TRJ;
-      fTemp: Extended;
-    begin
-      RJ['title'] := 'hello world! 你好,世界!';
-      RJ['a.num'] := 1;
-      RJ['a.hah'] := false;
-      RJ['b[2]'] := 505;
-      RJ['b[0]'] := 'first';
-      RJ['good'] := True;
-      RJ1 := RJ['c'];
-      RJ1['c1'] := 1.1;
-      RJ1['c2[2]'] := 2.33;
-      with RJ['x'] do
-      begin
-        items[1] := 100;
-        items[2] := '202';
-      end;
-      with RJ['y'] do
-      begin
-        items['ya'] := 'y1';
-        items['yb'] := -2;
-      end;
-      Memo1.Text := RJ.Format;
-      Memo1.Lines.Add('-----------------------------------------------------------');
-      fTemp := RJ['c.c2[3]'];
-      Memo1.Lines.Add('fTemp:' + fTemp.ToString);
-      fTemp := RJ['c.c3[3]'].ToFloat(-100);
-      Memo1.Lines.Add('fTemp:' + fTemp.ToString);
-      Memo1.Lines.Add(RJ['a.num'].ToStr('a.num not exist'));
-      Memo1.Lines.Add(RJ['none'].ToFloat(-1).ToString);
-      Memo1.Lines.Add(RJ['none.a3'].ToStr('none.a3 not exist'));
-      RJ.SaveToFile('test.json', 0);
-    end;
-
-    procedure TFormMain.btnOpenClick(Sender: TObject);
-    var
-      RJ: TRJ;
-      strTmp: string;
-    begin
-      RJ.LoadFromFile('test.json');
-      Memo1.Text := RJ.Format(8);
-      Memo1.Lines.Add('-----------------------ROOT--------------------------');
-      for var item in RJ do
-      begin
-        strTmp := Format('Index: %d  Key: %s  Value: %s',
-          [item.Index, item.Key, item.Format(0)]);
-        Memo1.Lines.Add(strTmp);
-      end;
-      Memo1.Lines.Add('-----------------------RJ[a]--------------------------');
-      for var item in RJ['a'] do
-      begin
-        strTmp := Format('Index: %d  Key: %s  Value: %s',
-          [item.Index, item.Key, item.Format(0)]);
-        Memo1.Lines.Add(strTmp);
-      end;
-      Memo1.Lines.Add('-----------------------RJ[b]--------------------------');
-      for var item in RJ['b'] do
-      begin
-        strTmp := Format('Index: %d  Key: %s  Value: %s',
-          [item.Index, item.Key, item.Format(0)]);
-        Memo1.Lines.Add(strTmp);
-      end;
-      Memo1.Lines.Add('-----------------------RJ[c]--------------------------');
-      for var i := 0 to RJ['c'].Count - 1 do
-      begin
-        strTmp := Format('Index: %d  Key: %s  Value: %s',
-          [RJ['c'].Pairs[i].Index, RJ['c'].Pairs[i].Key, RJ['c'].Pairs[i].Format(0)]);
-        Memo1.Lines.Add(strTmp);
-      end;
-    end;

+ 394 - 248
rjson.pas

@@ -1,7 +1,7 @@
 {
   TRJ - JSON Simple Read and Write
-  - v0.9.2
-  - 2024-09-06 by gale
+  - v0.9.4
+  - 2024-09-09 by gale
   - https://github.com/higale/RJSON
 }
 unit rjson;
@@ -9,76 +9,74 @@ unit rjson;
 interface
 
 uses
-  System.IOUtils, System.Classes, System.SysUtils, System.StrUtils, System.JSON,
-  System.Generics.Collections;
+  System.IOUtils, System.Classes, System.SysUtils, System.JSON, System.Generics.Collections;
 
 type
-  /// <summary>Alias for <see cref="TJSONObject"/>.</summary>
   TJObject = TJSONObject;
-  /// <summary>Alias for <see cref="TJSONArray"/>.</summary>
   TJArray = TJSONArray;
-  /// <summary>Alias for <see cref="TJSONValue"/>.</summary>
   TJValue = TJSONValue;
-  /// <summary>Alias for <see cref="TJSONString"/>.</summary>
   TJString = TJSONString;
-  /// <summary>Alias for <see cref="TJSONNumber"/>.</summary>
   TJNumber = TJSONNumber;
-  /// <summary>Alias for <see cref="TJSONBool"/>.</summary>
   TJBool = TJSONBool;
-  /// <summary>Alias for <see cref="TJSONNull"/>.</summary>
   TJNull = TJSONNull;
+  TJVType = type of TJValue;
 
-  /// <summary>
-  /// Type alias for the <see cref="TJSONValue"/> class.
-  /// </summary>
-  TJVType = type of TJSONValue;
-
-  /// <summary>
-  /// Interface for the root of a JSON structure.
-  /// </summary>
   IRJRoot = interface
-    function GetData: TJSONValue;
-    procedure SetData(const AValue: TJSONValue);
-    function ForceJV(AType: TJVType): TJSONValue;
-    property Data: TJSONValue read GetData write SetData;
+    ['{486F1FA6-2CDD-4124-98C5-CE7C398B7143}']
+    function GetData: TJValue;
+    procedure SetData(const AValue: TJValue);
+    function ForceData(AType: TJVType): TJValue;
+    property Data: TJValue read GetData write SetData;
   end;
 
-  /// <summary>
-  /// Class representing the root of a JSON structure, implementing the <see cref="IRJRoot"/> interface.
-  /// </summary>
   TRJRoot = class(TInterfacedObject, IRJRoot)
   private
-    FData: TJSONValue;
-    function GetData: TJSONValue;
-    procedure SetData(const AValue: TJSONValue);
-    function ForceJV(AType: TJVType): TJSONValue;
+    FData: TJValue;
+    function GetData: TJValue;
+    procedure SetData(const AValue: TJValue);
+    function ForceData(AType: TJVType): TJValue;
   public
-    constructor Create; overload;
-    constructor Create(const AValue: TJSONValue); overload;
+    constructor Create;
     destructor Destroy; override;
   end;
 
+  TRPath = record
+  private
+    FData: string;
+  public
+    class operator Implicit(const Value: string): TRPath;
+    class operator Implicit(Value: Integer): TRPath;
+    class operator Implicit(const [ref] Value: TRPath): string;
+  end;
+
   TRJEnumerator = class;
 
-  /// <summary>
-  /// Encapsulating common JSON data operation functionalities.<
-  /// </summary>
   TRJ = record
   private
-    FRoot: IRJRoot;
+    FIRoot: IRJRoot;
     FPath: string;
+    function GetRootRefCount: Integer;
+    function ForceRootJValue(const APath: string): TJValue;
     function LinkPath(const ALeft, ARight: string): string;
-    function GetJSONValue: TJSONValue; inline;
-    function GetItems(const APath: string): TRJ; overload;
-    function GetItems(AIndex: Integer): TRJ; overload; inline;
+    function GeTJValue: TJValue; inline;
+    function GetItems(const APath: TRPath): TRJ;
     function GetPairs(AIndex: Integer): TRJ;
     procedure SetValue(const [ref] AValue: TRJ);
-    procedure SetItems(const APath: string; const [ref] AValue: TRJ); overload;
-    procedure SetItems(AIndex: Integer; const [ref] AValue: TRJ); overload; inline;
+    procedure SetItems(const APath: TRPath; const [ref] AValue: TRJ);
+    function GetS(const APath: TRPath): string; overload;
+    procedure SetS(const APath: TRPath; AValue: string); overload;
+    function GetI(const APath: TRPath): Integer; overload;
+    procedure SetI(const APath: TRPath; AValue: Integer); overload;
+    function GetI64(const APath: TRPath): Int64; overload;
+    procedure SetI64(const APath: TRPath; AValue: Int64); overload;
+    function GetF(const APath: TRPath): Extended; overload;
+    procedure SetF(const APath: TRPath; AValue: Extended); overload;
+    function GetB(const APath: TRPath): boolean; overload;
+    procedure SetB(const APath: TRPath; AValue: boolean); overload;
     function GetCount: Integer;
     function GetIndex: Integer;
     function GetKey: string;
-    //function GetIsNil: Boolean;
+    function GetRoot: TRJ;
   public
     function GetEnumerator(): TRJEnumerator;
     class operator Initialize(out Dest: TRJ);
@@ -92,92 +90,50 @@ type
     class operator Implicit(const [ref] Value: TRJ): Int64;
     class operator Implicit(Value: Extended): TRJ;
     class operator Implicit(const [ref] Value: TRJ): Extended;
-    class operator Implicit(Value: Boolean): TRJ;
-    class operator Implicit(const [ref] Value: TRJ): Boolean;
-    class operator Implicit(const Value: TJSONValue): TRJ;
-    /// <summary>Attempts to convert an object to a string representation.</summary>
-    /// <param name="ADefault">A default value to return if the conversion fails.</param>
-    /// <returns>The converted string value, or the specified default value if the conversion fails.</returns>
+    class operator Implicit(Value: boolean): TRJ;
+    class operator Implicit(const [ref] Value: TRJ): boolean;
+    class operator Implicit(const Value: TJValue): TRJ;
+    class operator Implicit(const [ref] Value: TRJ): TJValue;
     function ToStr(const ADefault: string = ''): string;
-    /// <summary>Attempts to convert an object to an integer type.</summary>
-    /// <param name="ADefault">A default value to return if the conversion fails.</param>
-    /// <returns>The converted integer value, or the specified default value if the conversion fails.</returns>
     function ToInt(ADefault: Integer = 0): Integer;
-    /// <summary>Attempts to convert an object to a 64-bit integer type.</summary>
-    /// <param name="ADefault">A default value to return if the conversion fails.</param>
-    /// <returns>The converted 64-bit integer value, or the specified default value if the conversion fails.</returns>
     function ToInt64(ADefault: Int64 = 0): Int64;
-    /// <summary>Attempts to convert an object to a floating-point number.</summary>
-    /// <param name="ADefault">A default value to return if the conversion fails.</param>
-    /// <returns>The converted floating-point value, or the specified default value if the conversion fails.</returns>
     function ToFloat(ADefault: Extended = 0.0): Extended;
-    /// <summary>Attempts to convert an object to a boolean value.</summary>
-    /// <param name="ADefault">A default value to return if the conversion fails.</param>
-    /// <returns>The converted boolean value, or the specified default value if the conversion fails.</returns>
-    function ToBool(ADefault: Boolean = False): Boolean;
-    /// <summary>Gets or sets the item at the specified path.</summary>
-    /// <param name="APath">The path of the item.</param>
-    /// <value>The item at the specified path.</value>
-    property Items[const APath: string]: TRJ read GetItems write SetItems; default;
-    /// <summary>Gets or sets the item at the specified index.</summary>
-    /// <param name="AIndex">The index of the item.</param>
-    /// <value>The item at the specified index.</value>
-    property Items[AIndex: Integer]: TRJ read GetItems write SetItems; default;
-    /// <summary>Gets the pair at the specified index.</summary>
-    /// <param name="AIndex">The index of the pair.</param>
-    /// <value>The pair at the specified index.</value>
+    function ToBool(ADefault: boolean = False): boolean;
+
+    property Items[const APath: TRPath]: TRJ read GetItems write SetItems; default;
+    property S[const APath: TRPath]: string read GetS write SetS;
+    property I[const APath: TRPath]: Integer read GetI write SetI;
+    property I64[const APath: TRPath]: Int64 read GetI64 write SetI64;
+    property F[const APath: TRPath]: Extended read GetF write SetF;
+    property B[const APath: TRPath]: boolean read GetB write SetB;
     property Pairs[AIndex: Integer]: TRJ read GetPairs;
-    /// <summary>Gets the count of items.</summary>
-    /// <value>The count of items.</value>
     property Count: Integer read GetCount;
-    /// <summary>Gets the current index.</summary>
-    /// <value>The current index.</value>
     property Index: Integer read GetIndex;
-    /// <summary>Gets the key of the current item.</summary>
-    /// <value>The key of the current item.</value>
     property Key: string read GetKey;
-    /// <summary>Gets the root of the JSON structure.</summary>
-    /// <value>The root of the JSON structure.</value>
-    property Root: IRJRoot read FRoot;
-    /// <summary>Gets the current path in the JSON structure.</summary>
-    /// <value>The current path in the JSON structure.</value>
+    property RootRefCount: Integer read GetRootRefCount;
+    property Root: TRJ read GetRoot;
     property Path: string read FPath;
-    /// <summary>Determines whether the root is of the specified JSON value type.</summary>
-    /// <typeparam name="T">The type of JSON value to check against.</typeparam>
-    /// <returns><c>true</c> if the root is of the specified type; otherwise, <c>false</c>.</returns>
-    function RootIs<T: TJSONValue>: Boolean;
-    /// <summary>Determines whether the value is of the specified JSON value type.</summary>
-    /// <typeparam name="T">The type of JSON value to check against.</typeparam>
-    /// <returns><c>true</c> if the value is of the specified type; otherwise, <c>false</c>.</returns>
-    function ValueIs<T: TJSONValue>: Boolean;
-    /// <summary>Gets the JSON value.</summary>
-    /// <value>The JSON value.</value>
-    property JSONValue: TJSONValue read GetJSONValue;
-    /// <summary>Creates a clone of the JSON value.</summary>
-    /// <returns>A clone of the JSON value.</returns>
-    function CloneJSONValue: TJSONValue;
-    /// <summary>Resets the JSON value to its initial state.</summary>
+    property JValue: TJValue read GeTJValue;
+
+    function CloneJValue: TJValue;
+    function IsRoot: boolean; inline;
+    function RootIsJObject: boolean; inline;
+    function RootIsJArray: boolean; inline;
+    function IsJObject: boolean;
+    function IsJArray: boolean;
+    function IsJString: boolean;
+    function IsJNumber: boolean;
+    function IsJBool: boolean;
+    function IsJNull: boolean;
+    function IsNil: boolean;
     procedure Reset;
-    /// <summary>Formats the JSON value as a string with optional indentation.</summary>
-    /// <param name="Indentation">The number of spaces to use for indentation. Defaults to 4.</param>
-    /// <returns>The formatted JSON string.</returns>
-    function Format(Indentation: Integer = 4): string;
-    /// <summary>Parses the given JSON data string into a JSON value.</summary>
-    /// <param name="AData">The JSON data string to parse.</param>
-    /// <param name="AUseBool">Indicates whether to use boolean values for parsing. Defaults to <c>false</c>.</param>
-    /// <param name="ARaiseExc">Indicates whether to raise an exception on parsing errors. Defaults to <c>false</c>.</param>
-    procedure ParseJSONValue(const AData: string; AUseBool: Boolean = False; ARaiseExc: Boolean = False);
-    /// <summary>Loads JSON data from a file and parses it into a JSON value.</summary>
-    /// <param name="AFileName">The name of the file to load JSON data from.</param>
-    /// <param name="AUseBool">Indicates whether to use boolean values for parsing. Defaults to <c>false</c>.</param>
-    /// <param name="ARaiseExc">Indicates whether to raise an exception on parsing errors. Defaults to <c>false</c>.</param>
-    procedure LoadFromFile(const AFileName: string; AUseBool: Boolean = False; ARaiseExc: Boolean = False);
-    /// <summary>Saves the JSON value to a file with optional formatting.</summary>
-    /// <param name="AFileName">The name of the file to save the JSON data to.</param>
-    /// <param name="AIndentation">The number of spaces to use for indentation. Defaults to 4.</param>
-    /// <param name="AWriteBOM">Indicates whether to write a byte order mark (BOM) at the beginning of the file. Defaults to <c>false</c>.</param>
-    /// <param name="ATrailingLineBreak">Indicates whether to add a trailing line break at the end of the file. Defaults to <c>false</c>.</param>
-    procedure SaveToFile(const AFileName: string; AIndentation: Integer = 4; AWriteBOM: Boolean = False; ATrailingLineBreak: Boolean = False);
+    function ToString: string;
+    function ToJSON(AEncodeBelow32: boolean = true; AEncodeAbove127: boolean = true): string;
+    function Format(AIndentation: Integer = 4): string;
+    procedure ParseJValue(const AData: string; AUseBool: boolean = False; ARaiseExc: boolean = False);
+    procedure LoadFromFile(const AFileName: string; AUseBool: boolean = False; ARaiseExc: boolean = False);
+    procedure SaveToFile(const AFileName: string; AIndentation: Integer; AWriteBOM: boolean = False); overload;
+    procedure SaveToFile(const AFileName: string; AEncodeBelow32: boolean = true; AEncodeAbove127: boolean = true; AWriteBOM: boolean = False); overload;
   end;
 
   { Iterators }
@@ -188,7 +144,7 @@ type
     function GetCurrent: TRJ;
   public
     constructor Create(const [ref] AData: TRJ);
-    function MoveNext: Boolean;
+    function MoveNext: boolean;
     property Current: TRJ read GetCurrent;
   end;
 
@@ -203,29 +159,23 @@ begin
   FData := nil;
 end;
 
-constructor TRJRoot.Create(const AValue: TJSONValue);
-begin
-  inherited Create;
-  FData := AValue;
-end;
-
 destructor TRJRoot.Destroy;
 begin
   FData.Free;
   inherited;
 end;
 
-function TRJRoot.GetData: TJSONValue;
+function TRJRoot.GetData: TJValue;
 begin
   Result := FData;
 end;
 
-procedure TRJRoot.SetData(const AValue: TJSONValue);
+procedure TRJRoot.SetData(const AValue: TJValue);
 begin
   FData := AValue;
 end;
 
-function TRJRoot.ForceJV(AType: TJVType): TJSONValue;
+function TRJRoot.ForceData(AType: TJVType): TJValue;
 begin
   if not(FData is AType) then
   begin
@@ -237,60 +187,61 @@ end;
 
 { TRJRoot }
 { ============================================================================ }
-{ TJSONValueHelper }
+{ TJValueHelper }
 
 type
-  TJSONValueHelper = class helper for TJSONValue
+  TJValueHelper = class helper for TJValue
   private
-    procedure ObjSetItem(const AName: string; const AValue: TJSONValue);
-    procedure ArrFill<T: TJSONValue>(ACount: Integer);
-    procedure ArrInsert(const AIndex: Integer; const AValue: TJSONValue);
-    procedure ArrSetItem(AIndex: Integer; const AValue: TJSONValue);
+    procedure ObjSetItem(const AName: string; const AValue: TJValue);
+    procedure ArrFill<T: TJValue>(ACount: Integer);
+    procedure ArrInsert(const AIndex: Integer; const AValue: TJValue);
+    procedure ArrSetItem(AIndex: Integer; const AValue: TJValue);
     function ToType<T>(ADefault: T): T;
-    function GetOrCreate<T: TJSONValue>(AName: string): T;
-    procedure SetValue(const APath: string; const AValue: TJSONValue);
+    function GetOrCreate<T: TJValue>(AName: string): T;
+    procedure SetValue(const APath: string; const AValue: TJValue);
+    procedure TrySetValue(const APath: string; const AValue: TJValue);
   end;
 
-procedure TJSONValueHelper.ObjSetItem(const AName: string; const AValue: TJSONValue);
+procedure TJValueHelper.ObjSetItem(const AName: string; const AValue: TJValue);
 var
   pairTmp: TJSONPair;
 begin
-  pairTmp := TJSONObject(self).Get(AName);
+  pairTmp := TJObject(self).Get(AName);
   if pairTmp = nil then
-    TJSONObject(self).AddPair(AName, AValue)
+    TJObject(self).AddPair(AName, AValue)
   else
     pairTmp.JSONValue := AValue;
 end;
 
-procedure TJSONValueHelper.ArrFill<T>(ACount: Integer);
+procedure TJValueHelper.ArrFill<T>(ACount: Integer);
 begin
-  for var j := TJSONArray(self).Count to ACount do
-    TJSONArray(self).AddElement(T.Create);
+  for var j := TJArray(self).Count to ACount do
+    TJArray(self).AddElement(T.Create);
 end;
 
-procedure TJSONValueHelper.ArrInsert(const AIndex: Integer; const AValue: TJSONValue);
+procedure TJValueHelper.ArrInsert(const AIndex: Integer; const AValue: TJValue);
 begin
-  TJSONArray(self).AddElement(AValue);
-  for var i := AIndex to TJSONArray(self).Count - 2 do
-    TJSONArray(self).AddElement(TJSONArray(self).Remove(AIndex));
+  TJArray(self).AddElement(AValue);
+  for var I := AIndex to TJArray(self).Count - 2 do
+    TJArray(self).AddElement(TJArray(self).Remove(AIndex));
 end;
 
-procedure TJSONValueHelper.ArrSetItem(AIndex: Integer; const AValue: TJSONValue);
+procedure TJValueHelper.ArrSetItem(AIndex: Integer; const AValue: TJValue);
 begin
-  ArrFill<TJSONNull>(AIndex - 1);
-  if AIndex <= TJSONArray(self).Count - 1 then
-    TJSONArray(self).Remove(AIndex).Free;
+  ArrFill<TJNull>(AIndex - 1);
+  if AIndex <= TJArray(self).Count - 1 then
+    TJArray(self).Remove(AIndex).Free;
   ArrInsert(AIndex, AValue);
 end;
 
-procedure TJSONValueHelper.SetValue(const APath: string; const AValue: TJSONValue);
+procedure TJValueHelper.SetValue(const APath: string; const AValue: TJValue);
 var
   LParser: TJSONPathParser;
   preName: string;
-  jv: TJSONValue;
+  jv: TJValue;
 begin
   if APath.IsEmpty then
-    raise Exception.Create('TJSONValueHelper.SetValue: path cannot be empty');
+    raise Exception.Create('TJValueHelper.SetValue: path cannot be empty');
 
   jv := self;
   LParser := TJSONPathParser.Create(APath);
@@ -301,49 +252,63 @@ begin
     LParser.NextToken;
     case LParser.Token of
       TJSONPathParser.TToken.Name:
-        jv := jv.GetOrCreate<TJSONObject>(preName);
+        jv := jv.GetOrCreate<TJObject>(preName);
       TJSONPathParser.TToken.ArrayIndex:
-        jv := jv.GetOrCreate<TJSONArray>(preName);
+        jv := jv.GetOrCreate<TJArray>(preName);
       TJSONPathParser.TToken.Eof:
         begin
-          if jv is TJSONObject then
+          if jv is TJObject then
             jv.ObjSetItem(preName, AValue)
           else
             jv.ArrSetItem(preName.ToInteger, AValue);
           break;
         end;
     else
-      raise Exception.Create('TJSONValueHelper.SetValue, LParser.Token Error!');
+      raise Exception.Create('TJValueHelper.SetValue, LParser.Token Error!');
     end;
   end;
 end;
 
-function TJSONValueHelper.ToType<T>(ADefault: T): T;
+procedure TJValueHelper.TrySetValue(const APath: string; const AValue: TJValue);
+begin
+  try
+    SetValue(APath, AValue);
+  except
+    on E: Exception do
+    begin
+      AValue.Free;
+      raise Exception.Create(E.Message);
+    end;
+  end;
+
+end;
+
+function TJValueHelper.ToType<T>(ADefault: T): T;
 begin
   if self = nil then
     Exit(ADefault);
   try
-      Result := AsType<T>;
+    Result := AsType<T>;
   except
-      Result := ADefault;
+    Result := ADefault;
   end;
 end;
 
-function TJSONValueHelper.GetOrCreate<T>(AName: string): T;
+function TJValueHelper.GetOrCreate<T>(AName: string): T;
 begin
-  if self is TJSONObject then
+  if self is TJObject then
   begin
-    Result := T(TJSONObject(self).GetValue(AName));
+    Result := T(TJObject(self).GetValue(AName));
     if not(Result is T) then
     begin
       Result := T.Create;
       ObjSetItem(AName, Result);
     end;
   end
-  else if self is TJSONArray then
+  else if self is TJArray then
   begin
-    ArrFill<TJSONNull>(AName.ToInteger);
-    Result := T(TJSONArray(self).Items[AName.ToInteger]);
+    ArrFill<TJNull>(AName.ToInteger);
+    Result := T(TJArray(self).Items[AName.ToInteger]);
     if not(Result is T) then
     begin
       Result := T.Create;
@@ -356,7 +321,26 @@ begin
   end;
 end;
 
-{ TJSONValueHelper }
+{ TJValueHelper }
+{ ============================================================================ }
+{ TRPath }
+
+class operator TRPath.Implicit(const Value: string): TRPath;
+begin
+  Result.FData := Value;
+end;
+
+class operator TRPath.Implicit(Value: Integer): TRPath;
+begin
+  Result.FData := '[' + Value.ToString + ']';
+end;
+
+class operator TRPath.Implicit(const [ref] Value: TRPath): string;
+begin
+  Result := Value.FData;
+end;
+
+{ TRPath }
 { ============================================================================ }
 { TRJEnumerator }
 
@@ -369,25 +353,25 @@ end;
 
 function TRJEnumerator.GetCurrent: TRJ;
 var
-  jvTmp: TJSONValue;
+  jvTmp: TJValue;
 begin
   Result.Reset;
-  Result.FRoot := FPData^.FRoot;
-  jvTmp := FPData^.GetJSONValue;
-  if jvTmp is TJSONObject then
+  Result.FIRoot := FPData^.FIRoot;
+  jvTmp := FPData^.GeTJValue;
+  if jvTmp is TJObject then
   begin
     if FPData^.FPath = '' then
-      Result.FPath := TJSONObject(jvTmp).Pairs[FIndex].JsonString.Value
+      Result.FPath := TJObject(jvTmp).Pairs[FIndex].JsonString.Value
     else
-      Result.FPath := FPData^.FPath + '.' + TJSONObject(jvTmp).Pairs[FIndex].JsonString.Value;
+      Result.FPath := FPData^.FPath + '.' + TJObject(jvTmp).Pairs[FIndex].JsonString.Value;
   end
-  else if jvTmp is TJSONArray then
+  else if jvTmp is TJArray then
   begin
     Result.FPath := FPData^.FPath + '[' + FIndex.ToString + ']';
   end;
 end;
 
-function TRJEnumerator.MoveNext: Boolean;
+function TRJEnumerator.MoveNext: boolean;
 begin
   Inc(FIndex);
   Exit(FIndex < FPData^.Count)
@@ -404,13 +388,26 @@ end;
 
 class operator TRJ.Initialize(out Dest: TRJ);
 begin
-  Dest.FRoot := TRJRoot.Create;
+  Dest.FIRoot := TRJRoot.Create;
   Dest.FPath := '';
 end;
 
 class operator TRJ.Finalize(var Dest: TRJ);
 begin
-  Dest.FRoot := nil;
+  Dest.FIRoot := nil;
+end;
+
+function TRJ.GetRootRefCount: Integer;
+begin
+  Result := (FIRoot as TRJRoot).RefCount;
+end;
+
+function TRJ.ForceRootJValue(const APath: string): TJValue;
+begin
+  if APath.StartsWith('[') then
+    Result := FIRoot.ForceData(TJArray)
+  else
+    Result := FIRoot.ForceData(TJObject);
 end;
 
 function TRJ.LinkPath(const ALeft, ARight: string): string;
@@ -425,25 +422,25 @@ begin
     Result := ALeft + '.' + ARight;
 end;
 
-function TRJ.GetJSONValue: TJSONValue;
+function TRJ.GeTJValue: TJValue;
 begin
-  Result := FRoot.Data.FindValue(FPath);
+  Result := FIRoot.Data.FindValue(FPath);
 end;
 
-function TRJ.CloneJSONValue: TJSONValue;
+function TRJ.CloneJValue: TJValue;
 begin
-  Result := GetJSONValue;
+  Result := GeTJValue;
   if Result <> nil then
-    Result := Result.Clone as TJSONValue
+    Result := Result.Clone as TJValue
   else
-    Result := TJSONNull.Create;
+    Result := TJNull.Create;
 end;
 
 class operator TRJ.Assign(var Dest: TRJ; const [ref] Src: TRJ);
 begin
   if Dest.FPath.IsEmpty then
   begin
-    Dest.FRoot := Src.FRoot;
+    Dest.FIRoot := Src.FIRoot;
     Dest.FPath := Src.FPath;
   end
   else
@@ -454,7 +451,7 @@ end;
 
 class operator TRJ.Implicit(const Value: string): TRJ;
 begin
-  Result.FRoot.Data := TJSONString.Create(Value);
+  Result.FIRoot.Data := TJString.Create(Value);
 end;
 
 class operator TRJ.Implicit(const [ref] Value: TRJ): string;
@@ -464,7 +461,7 @@ end;
 
 class operator TRJ.Implicit(Value: Integer): TRJ;
 begin
-  Result.FRoot.Data := TJSONNumber.Create(Value);
+  Result.FIRoot.Data := TJNumber.Create(Value);
 end;
 
 class operator TRJ.Implicit(const [ref] Value: TRJ): Integer;
@@ -474,7 +471,7 @@ end;
 
 class operator TRJ.Implicit(Value: Int64): TRJ;
 begin
-  Result.FRoot.Data := TJSONNumber.Create(Value);
+  Result.FIRoot.Data := TJNumber.Create(Value);
 end;
 
 class operator TRJ.Implicit(const [ref] Value: TRJ): Int64;
@@ -484,7 +481,7 @@ end;
 
 class operator TRJ.Implicit(Value: Extended): TRJ;
 begin
-  Result.FRoot.Data := TJSONNumber.Create(Value);
+  Result.FIRoot.Data := TJNumber.Create(Value);
 end;
 
 class operator TRJ.Implicit(const [ref] Value: TRJ): Extended;
@@ -492,112 +489,184 @@ begin
   Result := Value.ToFloat(0.0);
 end;
 
-class operator TRJ.Implicit(Value: Boolean): TRJ;
+class operator TRJ.Implicit(Value: boolean): TRJ;
 begin
-  Result.FRoot.Data := TJSONBool.Create(Value);
+  Result.FIRoot.Data := TJBool.Create(Value);
 end;
 
-class operator TRJ.Implicit(const [ref] Value: TRJ): Boolean;
+class operator TRJ.Implicit(const [ref] Value: TRJ): boolean;
 begin
   Result := Value.ToBool(False);
 end;
 
-class operator TRJ.Implicit(const Value: TJSONValue): TRJ;
+class operator TRJ.Implicit(const Value: TJValue): TRJ;
 begin
-  Result.FRoot.Data := Value;
+  Result.FIRoot.Data := Value;
+end;
+
+class operator TRJ.Implicit(const [ref] Value: TRJ): TJValue;
+begin
+  Result := Value.GeTJValue;
 end;
 
 function TRJ.ToStr(const ADefault: string): string;
 begin
-  Result := FRoot.Data.FindValue(FPath).ToType<string>(ADefault);
+  Result := FIRoot.Data.FindValue(FPath).ToType<string>(ADefault);
 end;
 
 function TRJ.ToInt(ADefault: Integer = 0): Integer;
 begin
-  Result := FRoot.Data.FindValue(FPath).ToType<Integer>(ADefault);
+  Result := FIRoot.Data.FindValue(FPath).ToType<Integer>(ADefault);
 end;
 
 function TRJ.ToInt64(ADefault: Int64 = 0): Int64;
 begin
-  Result := FRoot.Data.FindValue(FPath).ToType<Int64>(ADefault);
+  Result := FIRoot.Data.FindValue(FPath).ToType<Int64>(ADefault);
 end;
 
 function TRJ.ToFloat(ADefault: Extended = 0.0): Extended;
 begin
-  Result := FRoot.Data.FindValue(FPath).ToType<Extended>(ADefault);
+  Result := FIRoot.Data.FindValue(FPath).ToType<Extended>(ADefault);
 end;
 
-function TRJ.ToBool(ADefault: Boolean = False): Boolean;
+function TRJ.ToBool(ADefault: boolean = False): boolean;
 begin
-  Result := FRoot.Data.FindValue(FPath).ToType<Boolean>(ADefault);
+  Result := FIRoot.Data.FindValue(FPath).ToType<boolean>(ADefault);
 end;
 
-function TRJ.GetItems(const APath: string): TRJ;
+function TRJ.GetItems(const APath: TRPath): TRJ;
 begin
-  Result.FRoot := FRoot;
+  Result.FIRoot := FIRoot;
   Result.FPath := LinkPath(FPath, APath);
 end;
 
-function TRJ.GetItems(AIndex: Integer): TRJ;
-begin
-  Result := GetItems('[' + AIndex.ToString + ']');
-end;
-
 function TRJ.GetPairs(AIndex: Integer): TRJ;
 var
-  jvTmp: TJSONValue;
+  jvTmp: TJValue;
 begin
-  jvTmp := GetJSONValue;
-  if (jvTmp is TJSONObject) then
-    Result := GetItems(TJSONObject(jvTmp).Pairs[AIndex].JsonString.Value);
+  jvTmp := GeTJValue;
+  if (jvTmp is TJObject) then
+    Result := GetItems(TJObject(jvTmp).Pairs[AIndex].JsonString.Value);
 end;
 
 procedure TRJ.SetValue(const [ref] AValue: TRJ);
 var
-  LValue: TJSONValue;
+  LValue: TJValue;
 begin
+{$IFDEF DEBUG}
   if FPath.IsEmpty then
     raise Exception.Create(' TRJ.SetValue: Path is empty');
-
-  LValue := AValue.CloneJSONValue;
+{$ENDIF}
+  LValue := AValue.CloneJValue;
   try
-    if FPath.StartsWith('[') then
-      FRoot.ForceJV(TJSONArray).SetValue(FPath, LValue)
-    else
-      FRoot.ForceJV(TJSONObject).SetValue(FPath, LValue);
+    ForceRootJValue(FPath).SetValue(FPath, LValue);
   except
     on E: Exception do
     begin
       LValue.Free;
-      raise Exception.Create(E.message);
+      raise Exception.Create(E.Message);
     end;
   end;
-
 end;
 
-procedure TRJ.SetItems(const APath: string; const [ref] AValue: TRJ);
+procedure TRJ.SetItems(const APath: TRPath; const [ref] AValue: TRJ);
 var
   tmp: TRJ;
 begin
-  tmp.FRoot := FRoot;
+  tmp.FIRoot := FIRoot;
   tmp.FPath := LinkPath(FPath, APath);
   tmp.SetValue(AValue)
 end;
 
-procedure TRJ.SetItems(AIndex: Integer; const [ref] AValue: TRJ);
+function TRJ.GetS(const APath: TRPath): string;
+var
+  LPath: string;
+begin
+  LPath := LinkPath(FPath, APath);
+  Result := ForceRootJValue(LPath).FindValue(LPath).ToType<string>('');
+end;
+
+procedure TRJ.SetS(const APath: TRPath; AValue: string);
+var
+  LPath: string;
+begin
+  LPath := LinkPath(FPath, APath);
+  ForceRootJValue(LPath).TrySetValue(LPath, TJString.Create(AValue));
+end;
+
+function TRJ.GetI(const APath: TRPath): Integer;
+var
+  LPath: string;
+begin
+  LPath := LinkPath(FPath, APath);
+  Result := ForceRootJValue(LPath).FindValue(LPath).ToType<Integer>(0);
+end;
+
+procedure TRJ.SetI(const APath: TRPath; AValue: Integer);
+var
+  LPath: string;
+begin
+  LPath := LinkPath(FPath, APath);
+  ForceRootJValue(LPath).TrySetValue(LPath, TJNumber.Create(AValue));
+end;
+
+function TRJ.GetI64(const APath: TRPath): Int64;
+var
+  LPath: string;
+begin
+  LPath := LinkPath(FPath, APath);
+  Result := ForceRootJValue(LPath).FindValue(LPath).ToType<Int64>(0);
+end;
+
+procedure TRJ.SetI64(const APath: TRPath; AValue: Int64);
+var
+  LPath: string;
 begin
-  SetItems('[' + AIndex.ToString + ']', AValue);
+  LPath := LinkPath(FPath, APath);
+  ForceRootJValue(LPath).TrySetValue(LPath, TJNumber.Create(AValue));
+end;
+
+function TRJ.GetF(const APath: TRPath): Extended;
+var
+  LPath: string;
+begin
+  LPath := LinkPath(FPath, APath);
+  Result := ForceRootJValue(LPath).FindValue(LPath).ToType<Extended>(0.0);
+end;
+
+procedure TRJ.SetF(const APath: TRPath; AValue: Extended);
+var
+  LPath: string;
+begin
+  LPath := LinkPath(FPath, APath);
+  ForceRootJValue(LPath).TrySetValue(LPath, TJNumber.Create(AValue));
+end;
+
+function TRJ.GetB(const APath: TRPath): boolean;
+var
+  LPath: string;
+begin
+  LPath := LinkPath(FPath, APath);
+  Result := ForceRootJValue(LPath).FindValue(LPath).ToType<boolean>(False);
+end;
+
+procedure TRJ.SetB(const APath: TRPath; AValue: boolean);
+var
+  LPath: string;
+begin
+  LPath := LinkPath(FPath, APath);
+  ForceRootJValue(LPath).TrySetValue(LPath, TJBool.Create(AValue));
 end;
 
 function TRJ.GetCount: Integer;
 var
-  jvTemp: TJSONValue;
+  jvTemp: TJValue;
 begin
-  jvTemp := GetJSONValue;
-  if jvTemp is TJSONArray then
-    Result := TJSONArray(jvTemp).Count
-  else if jvTemp is TJSONObject then
-    Result := TJSONObject(jvTemp).Count
+  jvTemp := GeTJValue;
+  if jvTemp is TJArray then
+    Result := TJArray(jvTemp).Count
+  else if jvTemp is TJObject then
+    Result := TJObject(jvTemp).Count
   else
     Result := 0;
 end;
@@ -619,60 +688,137 @@ begin
     Result := '';
 end;
 
-function TRJ.RootIs<T>: Boolean;
+function TRJ.GetRoot: TRJ;
+begin
+  Result.FIRoot := FIRoot;
+  // Result.FPath := '';
+end;
+
+function TRJ.IsRoot: boolean;
+begin
+  Result := FPath.IsEmpty;
+end;
+
+function TRJ.RootIsJObject: boolean;
+begin
+  Result := FIRoot.Data is TJObject;
+end;
+
+function TRJ.RootIsJArray: boolean;
+begin
+  Result := FIRoot.Data is TJArray;
+end;
+
+function TRJ.IsJObject: boolean;
+begin
+  Result := GeTJValue is TJObject;
+end;
+
+function TRJ.IsJArray: boolean;
 begin
-  Result := FRoot.Data is T;
+  Result := GeTJValue is TJArray;
 end;
 
-function TRJ.ValueIs<T>: Boolean;
+function TRJ.IsJString: boolean;
 begin
-  Result := GetJSONValue is T;
+  Result := GeTJValue is TJString;
+end;
+
+function TRJ.IsJNumber: boolean;
+begin
+  Result := GeTJValue is TJNumber;
+end;
+
+function TRJ.IsJBool: boolean;
+begin
+  Result := GeTJValue is TJBool;
+end;
+
+function TRJ.IsJNull: boolean;
+begin
+  Result := GeTJValue is TJNull;
+end;
+
+function TRJ.IsNil: boolean;
+begin
+  Result := GeTJValue = nil;
 end;
 
 procedure TRJ.Reset;
 begin
-  FRoot := TRJRoot.Create;
+  FIRoot := TRJRoot.Create;
   FPath := '';
 end;
 
-function TRJ.Format(Indentation: Integer): string;
+function TRJ.ToJSON(AEncodeBelow32: boolean = true; AEncodeAbove127: boolean = true): string;
 var
-  LValue: TJSONValue;
+  LValue: TJValue;
+  Options: TJSONAncestor.TJSONOutputOptions;
 begin
   Result := '';
-  LValue := GetJSONValue;
+  LValue := GeTJValue;
   if LValue <> nil then
   begin
-    if Indentation > 0 then
-      Result := LValue.Format(Indentation)
-    else
-      Result := LValue.ToString;
+    Options := [];
+    if AEncodeBelow32 then
+      Include(Options, TJSONAncestor.TJSONOutputOption.EncodeBelow32);
+    if AEncodeAbove127 then
+      Include(Options, TJSONAncestor.TJSONOutputOption.EncodeAbove127);
+    Result := LValue.ToJSON(Options);
   end;
 end;
 
-procedure TRJ.ParseJSONValue(const AData: string; AUseBool: Boolean; ARaiseExc: Boolean);
+function TRJ.ToString: string;
+begin
+  Result := ToJSON(False, False);
+end;
+
+function TRJ.Format(AIndentation: Integer): string;
+var
+  LValue: TJValue;
+begin
+  Result := '';
+  LValue := GeTJValue;
+  if LValue <> nil then
+    Result := LValue.Format(AIndentation)
+end;
+
+procedure TRJ.ParseJValue(const AData: string; AUseBool: boolean; ARaiseExc: boolean);
 begin
   Reset;
-  FRoot.Data := TJSONValue.ParseJSONValue(AData, AUseBool, ARaiseExc);
+  FIRoot.Data := TJValue.ParseJSONValue(AData, AUseBool, ARaiseExc);
 end;
 
-procedure TRJ.LoadFromFile(const AFileName: string; AUseBool: Boolean; ARaiseExc: Boolean);
+procedure TRJ.LoadFromFile(const AFileName: string; AUseBool: boolean; ARaiseExc: boolean);
 begin
-  ParseJSONValue(TFile.ReadAllText(AFileName, TEncoding.UTF8), AUseBool, ARaiseExc);
+  ParseJValue(TFile.ReadAllText(AFileName, TEncoding.UTF8), AUseBool, ARaiseExc);
 end;
 
-procedure TRJ.SaveToFile(const AFileName: string; AIndentation: Integer; AWriteBOM: Boolean; ATrailingLineBreak: Boolean);
+procedure TRJ.SaveToFile(const AFileName: string; AIndentation: Integer; AWriteBOM: boolean);
 var
   strs: TStrings;
 begin
   strs := TStringList.Create;
   try
     strs.WriteBOM := AWriteBOM;
-    strs.TrailingLineBreak := ATrailingLineBreak;
     strs.Text := Format(AIndentation);
     strs.SaveToFile(AFileName, TEncoding.UTF8);
   finally
-      strs.Free;
+    strs.Free;
+  end;
+end;
+
+procedure TRJ.SaveToFile(const AFileName: string; AEncodeBelow32: boolean = true; AEncodeAbove127: boolean = true; AWriteBOM: boolean = False);
+var
+  strs: TStrings;
+begin
+  strs := TStringList.Create;
+  try
+    strs.WriteBOM := AWriteBOM;
+    strs.Text := ToJSON(AEncodeBelow32, AEncodeAbove127);
+    strs.SaveToFile(AFileName, TEncoding.UTF8);
+  finally
+    strs.Free;
   end;
 end;