Jump to content

Parsing JSON objects in Delphi


Norm

Recommended Posts

This post explains how to parse a master/detail JSON object in Delphi for those interested.

It is an addendum to a post I added to the following thread about REST API:
http://forums.unigui.com/index.php?/topic/23222-using-unigui-rest-full-server/#comment-136637

I use here as an example an invoice object in JSON format received via an http POST request.
The procedure below parses the the JSON object and stores the invoice field values in a Stringlist for further processing

Assuming the object we have received looks like this (1 invoice header and 3 invoice details):
// {"invNo":"0001234", "invDate":"2023-06-21","customer":"Robert Smith", "invAmt":271.50,
//  "invDetails" :[{"seqNo":1, "productCode":"SPRINGS","description":"Galv 2.0m Tensile", "qty":2, "price":120.50},
//                 {"seqNo":2, "productCode":"LUB","description":"2cm Light Grease", "qty":1, "price":20.50},
//                 {"seqNo":3, "productCode":"FREIGHT","description":"Freiht Cost", "qty":1, "price":10.00}]
// }


//Some JSON Helper functions we'll use (Delphi unit required : System.JSON)
function getJsonCurrency(wObj: TJSONObject; wItem: String): Currency;
var
  aObjItem : TJSONString;
begin
  aObjItem := wObj.Get(wItem).JsonValue as TJSONString;
  Result := StrToFloat(aObjItem.Value);
end;

function getJsonDate(wObj: TJSONObject; wItem: String; fmt : TFormatSettings): Currency;
var
  aObjItem : TJSONString;
  aValue : String;
begin
  aObjItem := wObj.Get(wItem).JsonValue as TJSONString;
  aValue := aObjItem.Value;
  Result := StrToDate(aValue, fmt);
end;

function getJsonInteger(wObj: TJSONObject; wItem: String): Integer;
var
  aObjItem : TJSONString;
begin
  aObjItem := wObj.Get(wItem).JsonValue as TJSONString;
  Result := StrToInt(aObjItem.Value);
end;

function getJsonString(wObj: TJSONObject; wItem: String): String;
var
  aObjItem : TJSONString;
begin
  aObjItem := wObj.Get(wItem).JsonValue as TJSONString;
  Result := aObjItem.Value;
end;
//--

 

//Parsing the object

procedure ProcessJSONInvoice(wJSONInvoice: String);
type
  //Invoice Header Structure
  TInvoiceHeader = Record
    InvNo : String;
    Customer : String;
    InvDate : TDateTime;
    InvAmt : Currency;
  end;

  //Invoice Detail Structure
  TInvoiceDetail = Record
    LineSeq  : Integer;
    ItemCode : String;
    Description : String;
    Qty : Currency;
    Price : Currency;
  end;

var
  aJSONObj : TJSONObject;
  aDetailsArray : TJSONArray;

  InvoiceHeader : TInvoiceHeader;
  InvoiceDetail : TInvoiceDetail;

  aInvoiceData, aDataItems : TStringList;
  i : Integer;
  dateFmt : TFormatSettings;
begin
  aInvoiceData := TStringList.Create;
  aDataItems := TStringList.Create;
  aJSONObj := TJSONObject.ParseJSONValue(wJSONInvoice) as TJSONObject;
  try
    //Our Date Format
    dateFmt := TFormatSettings.Create(LOCALE_USER_DEFAULT);
    dateFmt.ShortDateFormat := 'yyyy/mm/dd';
    dateFmt.DateSeparator := '-';


    //Extract Invoice Header
    with InvoiceHeader do
    begin
      InvNo := getJsonString(aJSONObj, 'invNo');
      InvDate := getJsonDate(aJSONObj, 'invDate', dateFmt);
      Customer := getJsonString(aJSONObj, 'customer');
      InvAmt := getJsonCurrency(aJSONObj, 'invAmt');

      //Add to StringList
      aDataItems.Clear;
      aDataItems.Add('Header');
      aDataItems.Add(InvNo);
      aDataItems.Add(DateToStr(InvDate));
      aDataItems.Add(Customer);
      aDataItems.Add(FloatToStr(InvAmt));

      aInvoiceData.Add(aDataItems.CommaText);
    end;

    //Extract Invoice Details
    aDetailsArray := aJSONObj.Get('invDetails').JsonValue as TJSONArray;
    for i := 0 to aDetailsArray.Count - 1 do
    begin
      aJSONObj := aDetailsArray.Items[i] as TJSONObject;
      with InvoiceDetail do
      begin
        LineSeq := getJsonInteger(aJSONObj, 'seqNo');;
        ItemCode := getJsonString(aJSONObj, 'productCode');
        Description := getJsonString(aJSONObj, 'description');;
        Qty := getJsonCurrency(aJSONObj, 'qty');
        Price := getJsonCurrency(aJSONObj, 'price');;


        //Add Invoice Details to StringList
        aDataItems.Clear;
        aDataItems.Add('Detail');
        aDataItems.Add(IntToStr(LineSeq));
        aDataItems.Add(ItemCode);
        aDataItems.Add(Description);
        aDataItems.Add(FloatToStr(Qty));
        aDataItems.Add(FloatToStr(Price));
        aInvoiceData.Add(aDataItems.CommaText);
      end;
    end;
//Forward the stringlist for DB processing;
//  ProcessInvoice(aInvoiceData);
  finally
    aJSONObj.Free;
    aInvoiceData.Free;
    aDataItems.Free;
  end;
end;

 

Link to comment
Share on other sites

Why not just create Delphi classes

 

TInvDetail = class

  public

    seqNo: Integer;

    productCode: string;

    description: string;

    qty: Integer;

    price: Double;

  end;

 

TInvoice = class
  public
    invNo: string;
    invDate: TDateTime;
    customer: string;
    invAmt: Double;
    invDetails: TArray<TInvDetail>;
  end;

 

 

And then use

 

var

Invoice: TInvoice;

begin

Invoice := TJson.JsonToObject<TInvoice>(...)

 

???

Link to comment
Share on other sites

My intention was explain how to pass a JSON object in Delphi with the simplest code possible because someone asked me to, not to provide an OO and business logic tutorial. I thought the use of primitive Records instead of classes and the verbose transfer of the data via StringLists would  have made that obvious.

I'm sure nobody writes code like that.

 

Link to comment
Share on other sites

  • 2 months later...

Best solution:
1- https://jsontodelphi.com/
Paste your JSon example and it will generate all code and units to use it in your Delphi project in the best way available. (It's a "Marlon Nardin"'s project. You can get in touch with him at this very forum).

2- In your Delphi Project declare the units downloaded from the website and just use as a regular class.

3- There is no better solution than this one to Delphi/JSon, regarding accessing/importing JSon  data to your project. It should be native to RAD IDE tool's case.

4- Se Dataset Serializer at GitHub (https://github.com/viniciussanchez/dataset-serialize-adapter-restrequest4delphi) that  provide more powerful features and manipulating JSon as a regular Table.

5- Learn to use JS function JSON.stringify() and ajaxRequest, in all of its mess with uniURLFrame, and HTMLFrame. That's all you need to move data between webbrowser, forms and Delphi (unigui) tables and DB logic.

I'm working on a new book all about those topics and more.

Edited by Fred Montier
typos
  • Like 2
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...