Skip to content

pult/SuperObject.Delphi

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

66 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SuperObject.Delphi

Pascal (Delphi, FPC) json parser library SuperObject.

This version is compatible with Delphi and last FPC complilers.

Changes

  • v1.2
    • support of currency data type
    • right trim unquoted string
    • read Unicode Files and streams (Litle Endian with BOM)
    • Fix bug on javadate functions - windows nt compatibility
    • Now you can force to parse only the canonical syntax of JSON using the stric parameter
    • Delphi 2010 RTTI marshalling
    • Delphi 10.4 Sydney RTTI marshalling of "Managed Records"
    • ...

What is JSON ?

  • JSON (JavaScript Object Notation) is a lightweight data-interchange format.
  • It is easy for humans to read and write.
  • It is easy for machines to parse and generate.
  • It is based on a subset of the JavaScript Programming Language, Standard ECMA-262 3rd Edition - December 1999.
  • JSON is a text format that is completely language independent but uses conventions that are familiar to programmers.
  • These properties make JSON an ideal data-interchange language.
  • You can get more informations on json.org.
{
  "name": "Jon Snow", /* this is a comment */
  "dead": true,
  "telephones": ["000000000", "111111111111"],
  "age": 33,
  "size": 1.83,
  "adresses": [
    {
      "adress": "foo",
      "city": "The wall",
      "pc": 57000
    },
    {
      "adress": "foo",
      "city": "Winterfell",
      "pc": 44000
    }
  ]
}

Parsing a JSON data structure

var
  obj: ISuperObject;
begin
  obj := SO('{"foo": true}');
  obj := TSuperObject.ParseString('{"foo": true}');
  obj := TSuperObject.ParseStream(stream);
  obj := TSuperObject.ParseFile(FileName);
end;

Accessing data

There isn't individual datastructure for each supported data types. They are all an object: the ISuperObject.

  val := obj.AsString;
  val := obj.AsInteger;
  val := obj.AsBoolean;
  val := obj.AsDouble;
  val := obj.AsArray;
  val := obj.AsObject;
  val := obj.AsMethod;

How to read a property value of an object ?

  val := obj.AsObject.S['foo']; // get a string
  val := obj.AsObject.I['foo']; // get an Int64
  val := obj.AsObject.B['foo']; // get a Boolean
  val := obj.AsObject.D['foo']; // get a Double
  val := obj.AsObject.O['foo']; // get an Object (default)
  val := obj.AsObject.M['foo']; // get a Method
  val := obj.AsObject.N['foo']; // get a null object

How to read a value from an array ?

  // the advanced way
  val := obj.AsArray.S[0]; // get a string
  val := obj.AsArray.I[0]; // get an Int64
  val := obj.AsArray.B[0]; // get a Boolean
  val := obj.AsArray.D[0]; // get a Double
  val := obj.AsArray.O[0]; // get an Object (default)
  val := obj.AsArray.M[0]; // get a Method
  val := obj.AsArray.N[0]; // get a null object

Using paths

Using paths is a very productive method to find an object when you know where is it. This is some usage cases:

  obj['foo']; // get a property
  obj['123']; // get an item array
  obj['foo.list']; // get a property from an object
  obj['foo[123]']; // get an item array from an object
  obj['foo(1,2,3)']; // call a method
  obj['foo[]'] := value; // add an item array

you also can encapsulate paths:

  obj := so('{"index": 1, "items": ["item 1", "item 2", "item 3"]}');
  obj['items[index]'] // return "item 2"

or recreate a new data structure from another:

  obj := so('{"index": 1, "items": ["item 1", "item 2", "item 3"]}');
  obj['{"item": items[index], "index": index}'] // return {"item": "item 2", "index": 1}

Browsing data structure

Using Delphi enumerator.

Using Delphi enumerator you can browse item's array or property's object value in the same maner.

var
  item: ISuperObject;
begin
  for item in obj['items'] do ...

you can also browse the keys and values of an object like this:

var
  item: TSuperAvlEntry;
begin
  for item in obj.AsObject do ...
  begin
    item.Name;
    item.Value;
  end;

Browsing object properties without enumerator

var
  item: TSuperObjectIter;
begin
  if ObjectFindFirst(obj, item) then
  repeat
    item.key;
    item.val;
  until not ObjectFindNext(item);
  ObjectFindClose(item);

Browsing array items without enumerator

var
  item: Integer;
begin
  for item := 0 to obj.AsArray.Length - 1 do
    obj.AsArray[item]

RTTI & marshalling in Delphi 2010

type
  TData = record
    str: string;
    int: Integer;
    bool: Boolean;
    flt: Double;
  end;
var
  ctx: TSuperRttiContext;
  data: TData;
  obj: ISuperObject;
begin
  ctx := TSuperRttiContext.Create;
  try
    data := ctx.AsType<TData>(SO('{str: "foo", int: 123, bool: true, flt: 1.23}'));
    obj := ctx.AsJson<TData>(data);
  finally
    ctx.Free;
  end;
end;

Saving data

  obj.AsJSon(options);
  obj.SaveTo(stream);
  obj.SaveTo(filename);

Helpers

  SO(['prop1', true, 'prop2', 123]); // return an object {"prop1": true, "prop2": 123}
  SA([true, 123]); // return an array [true, 123]

Non canonical forms

The SuperObject is able to parse non canonical forms.

// unquoted identifiers
SO('{foo: true}');
// unescaped or unquoted strings
SO('{собственность: bla bla bla}');
// excadecimal
SO('{foo: \xFF}');

Additional examples

Get a Json string:

 function TDataModule3.GetSearchLostStatus: string;
 var
  X: ISuperObject;
 begin
  X := SO;
  with FServiceThread do
  begin
   X.B['NowSearchForFile'] := NowSearchForFile;
   X.S['LastLostFile'] := LastLostFile;
   X.B['NowSearchForRec'] := NowSearchForRec;
   X.S['LostRecProgress'] := LostRecProgress;
  end;
  Result := X.AsJSON;
 end;

Get data back from the Json string:

 procedure TForm2.SetSearchLostStatus(const Params: string);
 var
  s: string;
  X: ISuperObject;
 begin
  X := TSuperObject.ParseString(PChar(Params), True);
  FNowSearchForFile := not X.B['NowSearchForFile'];
  FLastLostFile := X.S['LastLostFile'];
  FNowSearchForRec := X.B['NowSearchForRec'];
  FLostRecProgress := X.I['LostRecProgress'];
 end;

An array usage:

 procedure TForm4.SetQueueStatus(const Params: string);
 var
  j: integer;
  X:  ISuperObject;
  X1: TSuperArray;
  s: string;
 begin
  X  := TSuperObject.ParseString(PChar(s), True);
  X1 := X.A['Queues'];
  StringGrid1.RowCount := X1.Length + 1;
  for j := 0 to X1.Length - 1 do
   with StringGrid1, X1[j] do
   begin
    Cells[0, j + 1] := S['NAME'];
    if j = 0 then
     Cells[1, j + 1] := S['FILES_QUEUED1'] + ' + ' + S['FILES_QUEUED2']
    else
     Cells[1, j + 1] := S['FILES_QUEUED'];
    Cells[2, j + 1] := S['STATUS'];
    Cells[3, j + 1] := S['FILES_DONE'];
    Cells[4, j + 1] := S['FILES_SKIPPED'];
   end;
 end;

Path usage:

 var s: string; json, field: iSuperObject;
 ....
  field := json.O['Document.CurrentItems.DocumentItem.Fields.FieldValue[1].Value'];
  s := json.O['Value'].AsString;

Releases

No releases published

Packages

No packages published

Languages