|
@@ -36,14 +36,17 @@ type
|
|
TFormatOption = (foSingleLineArray, // Array without CR/LF : all on one line
|
|
TFormatOption = (foSingleLineArray, // Array without CR/LF : all on one line
|
|
foSingleLineObject, // Object without CR/LF : all on one line
|
|
foSingleLineObject, // Object without CR/LF : all on one line
|
|
foDoNotQuoteMembers, // Do not quote object member names.
|
|
foDoNotQuoteMembers, // Do not quote object member names.
|
|
- foUseTabchar); // Use tab characters instead of spaces.
|
|
|
|
|
|
+ foUseTabchar, // Use tab characters instead of spaces.
|
|
|
|
+ foSkipWhiteSpace); // Do not use whitespace at all
|
|
TFormatOptions = set of TFormatOption;
|
|
TFormatOptions = set of TFormatOption;
|
|
|
|
|
|
Const
|
|
Const
|
|
DefaultIndentSize = 2;
|
|
DefaultIndentSize = 2;
|
|
DefaultFormat = [];
|
|
DefaultFormat = [];
|
|
AsJSONFormat = [foSingleLineArray,foSingleLineObject]; // These options make FormatJSON behave as AsJSON
|
|
AsJSONFormat = [foSingleLineArray,foSingleLineObject]; // These options make FormatJSON behave as AsJSON
|
|
-
|
|
|
|
|
|
+ AsCompressedJSON = [foSingleLineArray,foSingleLineObject,foskipWhiteSpace]; // These options make FormatJSON behave as AsJSON with TJSONData.CompressedJSON=True
|
|
|
|
+ AsCompactJSON = [foSingleLineArray,foSingleLineObject,foskipWhiteSpace,foDoNotQuoteMembers]; // These options make FormatJSON behave as AsJSON with TJSONData.CompressedJSON=True and TJSONObject.UnquotedMemberNames=True
|
|
|
|
+
|
|
Type
|
|
Type
|
|
TJSONData = Class;
|
|
TJSONData = Class;
|
|
|
|
|
|
@@ -68,6 +71,8 @@ Type
|
|
|
|
|
|
TJSONData = class(TObject)
|
|
TJSONData = class(TObject)
|
|
private
|
|
private
|
|
|
|
+ Const
|
|
|
|
+ ElementSeps : Array[Boolean] of TJSONStringType = (', ',',');
|
|
Class Var FCompressedJSON : Boolean;
|
|
Class Var FCompressedJSON : Boolean;
|
|
Class Var FElementSep : TJSONStringType;
|
|
Class Var FElementSep : TJSONStringType;
|
|
class procedure DetermineElementSeparators;
|
|
class procedure DetermineElementSeparators;
|
|
@@ -103,6 +108,7 @@ Type
|
|
public
|
|
public
|
|
Constructor Create; virtual;
|
|
Constructor Create; virtual;
|
|
Procedure Clear; virtual; Abstract;
|
|
Procedure Clear; virtual; Abstract;
|
|
|
|
+ Procedure DumpJSON(S : TStream);
|
|
// Get enumerator
|
|
// Get enumerator
|
|
function GetEnumerator: TBaseJSONEnumerator; virtual;
|
|
function GetEnumerator: TBaseJSONEnumerator; virtual;
|
|
Function FindPath(Const APath : TJSONStringType) : TJSONdata;
|
|
Function FindPath(Const APath : TJSONStringType) : TJSONdata;
|
|
@@ -442,7 +448,13 @@ Type
|
|
|
|
|
|
TJSONObject = class(TJSONData)
|
|
TJSONObject = class(TJSONData)
|
|
private
|
|
private
|
|
- Class var FUnquotedElementNames: Boolean;
|
|
|
|
|
|
+ Const
|
|
|
|
+ ElementStart : Array[Boolean] of TJSONStringType = ('"','');
|
|
|
|
+ SpacedQuoted : Array[Boolean] of TJSONStringType = ('" : ',' : ');
|
|
|
|
+ UnSpacedQuoted : Array[Boolean] of TJSONStringType = ('":',':');
|
|
|
|
+ ObjStartSeps : Array[Boolean] of TJSONStringType = ('{ ','{');
|
|
|
|
+ ObjEndSeps : Array[Boolean] of TJSONStringType = (' }','}');
|
|
|
|
+ Class var FUnquotedMemberNames: Boolean;
|
|
Class var FObjStartSep,FObjEndSep,FElementEnd,FElementStart : TJSONStringType;
|
|
Class var FObjStartSep,FObjEndSep,FElementEnd,FElementStart : TJSONStringType;
|
|
Class procedure DetermineElementQuotes;
|
|
Class procedure DetermineElementQuotes;
|
|
Private
|
|
Private
|
|
@@ -469,8 +481,8 @@ Type
|
|
procedure SetObjects(const AName : String; const AValue: TJSONObject);
|
|
procedure SetObjects(const AName : String; const AValue: TJSONObject);
|
|
procedure SetQWords(AName : String; AValue: QWord);
|
|
procedure SetQWords(AName : String; AValue: QWord);
|
|
procedure SetStrings(const AName : String; const AValue: TJSONStringType);
|
|
procedure SetStrings(const AName : String; const AValue: TJSONStringType);
|
|
- class function GetUnquotedElementNames: Boolean; static;
|
|
|
|
- class procedure SetUnquotedElementNames(AValue: Boolean); static;
|
|
|
|
|
|
+ class function GetUnquotedMemberNames: Boolean; static;
|
|
|
|
+ class procedure SetUnquotedMemberNames(AValue: Boolean); static;
|
|
protected
|
|
protected
|
|
Function DoFindPath(Const APath : TJSONStringType; Out NotFound : TJSONStringType) : TJSONdata; override;
|
|
Function DoFindPath(Const APath : TJSONStringType; Out NotFound : TJSONStringType) : TJSONdata; override;
|
|
Procedure Converterror(From : Boolean);
|
|
Procedure Converterror(From : Boolean);
|
|
@@ -498,7 +510,7 @@ Type
|
|
Constructor Create(const Elements : Array of Const); overload;
|
|
Constructor Create(const Elements : Array of Const); overload;
|
|
destructor Destroy; override;
|
|
destructor Destroy; override;
|
|
class function JSONType: TJSONType; override;
|
|
class function JSONType: TJSONType; override;
|
|
- Class Property UnquotedElementNames : Boolean Read GetUnquotedElementNames Write SetUnquotedElementNames;
|
|
|
|
|
|
+ Class Property UnquotedMemberNames : Boolean Read GetUnquotedMemberNames Write SetUnquotedMemberNames;
|
|
Function Clone : TJSONData; override;
|
|
Function Clone : TJSONData; override;
|
|
function GetEnumerator: TBaseJSONEnumerator; override;
|
|
function GetEnumerator: TBaseJSONEnumerator; override;
|
|
// Examine
|
|
// Examine
|
|
@@ -1011,6 +1023,52 @@ begin
|
|
Clear;
|
|
Clear;
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+procedure TJSONData.DumpJSON(S: TStream);
|
|
|
|
+
|
|
|
|
+ Procedure W(T : String);
|
|
|
|
+
|
|
|
|
+ begin
|
|
|
|
+ if (T<>'') then
|
|
|
|
+ S.WriteBuffer(T[1],Length(T)*SizeOf(Char));
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+Var
|
|
|
|
+ I,C : Integer;
|
|
|
|
+ O : TJSONObject;
|
|
|
|
+
|
|
|
|
+begin
|
|
|
|
+ Case JSONType of
|
|
|
|
+ jtObject :
|
|
|
|
+ begin
|
|
|
|
+ O:=TJSONObject(Self);
|
|
|
|
+ W('{');
|
|
|
|
+ For I:=0 to O.Count-1 do
|
|
|
|
+ begin
|
|
|
|
+ if (I>0) then
|
|
|
|
+ W(',');
|
|
|
|
+ W('"');
|
|
|
|
+ W(StringToJSONString(O.Names[i]));
|
|
|
|
+ W('":');
|
|
|
|
+ O.Items[I].DumpJSON(S);
|
|
|
|
+ end;
|
|
|
|
+ W('}');
|
|
|
|
+ end;
|
|
|
|
+ jtArray :
|
|
|
|
+ begin
|
|
|
|
+ W('[');
|
|
|
|
+ For I:=0 to Count-1 do
|
|
|
|
+ begin
|
|
|
|
+ if (I>0) then
|
|
|
|
+ W(',');
|
|
|
|
+ Items[I].DumpJSON(S);
|
|
|
|
+ end;
|
|
|
|
+ W(']');
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ W(AsJSON)
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
class function TJSONData.GetCompressedJSON: Boolean; static;
|
|
class function TJSONData.GetCompressedJSON: Boolean; static;
|
|
begin
|
|
begin
|
|
Result:=FCompressedJSON;
|
|
Result:=FCompressedJSON;
|
|
@@ -1018,8 +1076,6 @@ end;
|
|
|
|
|
|
class procedure TJSONData.DetermineElementSeparators;
|
|
class procedure TJSONData.DetermineElementSeparators;
|
|
|
|
|
|
-Const
|
|
|
|
- ElementSeps : Array[Boolean] of TJSONStringType = (', ',',');
|
|
|
|
|
|
|
|
begin
|
|
begin
|
|
FElementSep:=ElementSeps[FCompressedJSON];
|
|
FElementSep:=ElementSeps[FCompressedJSON];
|
|
@@ -1963,25 +2019,31 @@ function TJSONArray.DoFormatJSON(Options: TFormatOptions; CurrentIndent,
|
|
|
|
|
|
Var
|
|
Var
|
|
I : Integer;
|
|
I : Integer;
|
|
|
|
+ MultiLine : Boolean;
|
|
|
|
+ SkipWhiteSpace : Boolean;
|
|
|
|
+ Ind : String;
|
|
|
|
|
|
begin
|
|
begin
|
|
Result:='[';
|
|
Result:='[';
|
|
- if not (foSingleLineArray in Options) then
|
|
|
|
|
|
+ MultiLine:=Not (foSingleLineArray in Options);
|
|
|
|
+ SkipWhiteSpace:=foSkipWhiteSpace in Options;
|
|
|
|
+ Ind:=IndentString(Options, CurrentIndent+Indent);
|
|
|
|
+ if MultiLine then
|
|
Result:=Result+sLineBreak;
|
|
Result:=Result+sLineBreak;
|
|
For I:=0 to Count-1 do
|
|
For I:=0 to Count-1 do
|
|
begin
|
|
begin
|
|
- if not (foSingleLineArray in Options) then
|
|
|
|
- Result:=Result+IndentString(Options, CurrentIndent+Indent);
|
|
|
|
|
|
+ if MultiLine then
|
|
|
|
+ Result:=Result+Ind;
|
|
Result:=Result+Items[i].DoFormatJSON(Options,CurrentIndent+Indent,Indent);
|
|
Result:=Result+Items[i].DoFormatJSON(Options,CurrentIndent+Indent,Indent);
|
|
If (I<Count-1) then
|
|
If (I<Count-1) then
|
|
- if (foSingleLineArray in Options) then
|
|
|
|
- Result:=Result+', '
|
|
|
|
|
|
+ if MultiLine then
|
|
|
|
+ Result:=Result+','
|
|
else
|
|
else
|
|
- Result:=Result+',';
|
|
|
|
- if not (foSingleLineArray in Options) then
|
|
|
|
|
|
+ Result:=Result+ElementSeps[SkipWhiteSpace];
|
|
|
|
+ if MultiLine then
|
|
Result:=Result+sLineBreak
|
|
Result:=Result+sLineBreak
|
|
end;
|
|
end;
|
|
- if not (foSingleLineArray in Options) then
|
|
|
|
|
|
+ if MultiLine then
|
|
Result:=Result+IndentString(Options, CurrentIndent);
|
|
Result:=Result+IndentString(Options, CurrentIndent);
|
|
Result:=Result+']';
|
|
Result:=Result+']';
|
|
end;
|
|
end;
|
|
@@ -2337,9 +2399,9 @@ begin
|
|
Result:=Getelements(Aname).JSONType;
|
|
Result:=Getelements(Aname).JSONType;
|
|
end;
|
|
end;
|
|
|
|
|
|
-class function TJSONObject.GetUnquotedElementNames: Boolean; static;
|
|
|
|
|
|
+class function TJSONObject.GetUnquotedMemberNames: Boolean; static;
|
|
begin
|
|
begin
|
|
- Result:=FUnquotedElementNames;
|
|
|
|
|
|
+ Result:=FUnquotedMemberNames;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TJSONObject.SetArrays(const AName : String; const AValue: TJSONArray);
|
|
procedure TJSONObject.SetArrays(const AName : String; const AValue: TJSONArray);
|
|
@@ -2404,28 +2466,21 @@ end;
|
|
|
|
|
|
class procedure TJSONObject.DetermineElementQuotes;
|
|
class procedure TJSONObject.DetermineElementQuotes;
|
|
|
|
|
|
-Const
|
|
|
|
- ElementStart : Array[Boolean] of TJSONStringType = ('"','');
|
|
|
|
- SpacedQuoted : Array[Boolean] of TJSONStringType = ('" : ',' : ');
|
|
|
|
- UnSpacedQuoted : Array[Boolean] of TJSONStringType = ('":',':');
|
|
|
|
- ObjStartSeps : Array[Boolean] of TJSONStringType = ('{ ','{');
|
|
|
|
- ObjEndSeps : Array[Boolean] of TJSONStringType = (' }','}');
|
|
|
|
-
|
|
|
|
begin
|
|
begin
|
|
FObjStartSep:=ObjStartSeps[TJSONData.FCompressedJSON];
|
|
FObjStartSep:=ObjStartSeps[TJSONData.FCompressedJSON];
|
|
FObjEndSep:=ObjEndSeps[TJSONData.FCompressedJSON];
|
|
FObjEndSep:=ObjEndSeps[TJSONData.FCompressedJSON];
|
|
if TJSONData.FCompressedJSON then
|
|
if TJSONData.FCompressedJSON then
|
|
- FElementEnd:=UnSpacedQuoted[FUnquotedElementNames]
|
|
|
|
|
|
+ FElementEnd:=UnSpacedQuoted[FUnquotedMemberNames]
|
|
else
|
|
else
|
|
- FElementEnd:=SpacedQuoted[FUnquotedElementNames];
|
|
|
|
- FElementStart:=ElementStart[FUnquotedElementNames]
|
|
|
|
|
|
+ FElementEnd:=SpacedQuoted[FUnquotedMemberNames];
|
|
|
|
+ FElementStart:=ElementStart[FUnquotedMemberNames]
|
|
end;
|
|
end;
|
|
|
|
|
|
-class procedure TJSONObject.SetUnquotedElementNames(AValue: Boolean); static;
|
|
|
|
|
|
+class procedure TJSONObject.SetUnquotedMemberNames(AValue: Boolean); static;
|
|
|
|
|
|
begin
|
|
begin
|
|
- if FUnquotedElementNames=AValue then exit;
|
|
|
|
- FUnquotedElementNames:=AValue;
|
|
|
|
|
|
+ if FUnquotedMemberNames=AValue then exit;
|
|
|
|
+ FUnquotedMemberNames:=AValue;
|
|
DetermineElementQuotes;
|
|
DetermineElementQuotes;
|
|
end;
|
|
end;
|
|
|
|
|
|
@@ -2664,33 +2719,42 @@ function TJSONObject.DoFormatJSON(Options: TFormatOptions; CurrentIndent,
|
|
Var
|
|
Var
|
|
i : Integer;
|
|
i : Integer;
|
|
S : TJSONStringType;
|
|
S : TJSONStringType;
|
|
-
|
|
|
|
-
|
|
|
|
|
|
+ MultiLine,UseQuotes, SkipWhiteSpace : Boolean;
|
|
|
|
+ NSep,Sep,Ind : String;
|
|
begin
|
|
begin
|
|
Result:='';
|
|
Result:='';
|
|
- CurrentIndent:=CurrentIndent+Indent;
|
|
|
|
|
|
+ UseQuotes:=Not (foDoNotQuoteMembers in options);
|
|
|
|
+ MultiLine:=Not (foSingleLineObject in Options);
|
|
|
|
+ SkipWhiteSpace:=foSkipWhiteSpace in Options;
|
|
|
|
+ CurrentIndent:=CurrentIndent+Indent;
|
|
|
|
+ Ind:=IndentString(Options, CurrentIndent);
|
|
|
|
+ If SkipWhiteSpace then
|
|
|
|
+ NSep:=':'
|
|
|
|
+ else
|
|
|
|
+ NSep:=' : ';
|
|
|
|
+ If MultiLine then
|
|
|
|
+ Sep:=','+SLineBreak+Ind
|
|
|
|
+ else if SkipWhiteSpace then
|
|
|
|
+ Sep:=','
|
|
|
|
+ else
|
|
|
|
+ Sep:=', ';
|
|
For I:=0 to Count-1 do
|
|
For I:=0 to Count-1 do
|
|
begin
|
|
begin
|
|
- If (Result<>'') then
|
|
|
|
- begin
|
|
|
|
- If (foSingleLineObject in Options) then
|
|
|
|
- Result:=Result+', '
|
|
|
|
- else
|
|
|
|
- Result:=Result+','+SLineBreak;
|
|
|
|
- end;
|
|
|
|
- If not (foSingleLineObject in Options) then
|
|
|
|
- Result:=Result+IndentString(Options,CurrentIndent);
|
|
|
|
|
|
+ If (I>0) then
|
|
|
|
+ Result:=Result+Sep
|
|
|
|
+ else If MultiLine then
|
|
|
|
+ Result:=Result+Ind;
|
|
S:=StringToJSONString(Names[i]);
|
|
S:=StringToJSONString(Names[i]);
|
|
- If not (foDoNotQuoteMembers in options) then
|
|
|
|
|
|
+ If UseQuotes then
|
|
S:='"'+S+'"';
|
|
S:='"'+S+'"';
|
|
- Result:=Result+S+' : '+Items[I].DoFormatJSON(Options,CurrentIndent,Indent);
|
|
|
|
|
|
+ Result:=Result+S+NSep+Items[I].DoFormatJSON(Options,CurrentIndent,Indent);
|
|
end;
|
|
end;
|
|
If (Result<>'') then
|
|
If (Result<>'') then
|
|
begin
|
|
begin
|
|
- if (foSingleLineObject in Options) then
|
|
|
|
- Result:='{ '+Result+' }'
|
|
|
|
- else
|
|
|
|
|
|
+ if MultiLine then
|
|
Result:='{'+sLineBreak+Result+sLineBreak+indentString(options,CurrentIndent-Indent)+'}'
|
|
Result:='{'+sLineBreak+Result+sLineBreak+indentString(options,CurrentIndent-Indent)+'}'
|
|
|
|
+ else
|
|
|
|
+ Result:=ObjStartSeps[SkipWhiteSpace]+Result+ObjEndSeps[SkipWhiteSpace]
|
|
end
|
|
end
|
|
else
|
|
else
|
|
Result:='{}';
|
|
Result:='{}';
|