DMarlon Studio

Lesson 19 · 19 of 20

JSON with fpjson · Pascal

Read and build JSON in Free Pascal with fpjson and jsonparser: walk an order, add up its lines and reply with a brand new JSON object.

Pascal · JSON with fpjson in DMarlon Studio: the example's code and its output in the terminal

The `fpjson` unit represents JSON as Pascal objects (TJSONObject, TJSONArray, numbers and strings), and `jsonparser` adds the parser. `GetJSON` turns the Incoming text into that tree and returns the root, which is treated as an object here with as TJSONObject.

Values are read by name and type: order.Integers['id'], line.Strings['sku'], order.Arrays['lines']. `FindPath('customer.name')` goes down several levels at once using a dot-separated path. If a name is missing or the type does not match, an exception is raised.

The for item in loop walks the array of lines; each item is a TJSONEnum and its Value is the line object. The total is added up in whole cents, which also sidesteps an fpjson quirk: numbers with decimals come out in scientific notation when turned into text.

To build JSON, TJSONObject.Create([...]) takes name-value pairs, and Add appends more, even a whole TJSONArray. `AsJSON` writes it on one line (FormatJSON would indent it). Every object owns what it contains: a single Free on the root releases the whole tree, and the two try ... finally blocks make sure that happens.

Code · main.pas

program main;uses SysUtils, fpjson, jsonparser;const  Incoming = '{"id": 1042, "customer": {"name": "Lucia Romero", "city": "Malaga"},' +    ' "lines": [{"sku": "MUG-01", "qty": 2, "cents": 850},' +    ' {"sku": "TEA-12", "qty": 1, "cents": 1295}]}';var  order, line, reply: TJSONObject;  item: TJSONEnum;  total: Integer = 0;begin  order := GetJSON(Incoming) as TJSONObject;  // parse the text into objects  try    WriteLn('Order ', order.Integers['id'], ' for ', order.FindPath('customer.name').AsString);    for item in order.Arrays['lines'] do    begin      line := item.Value as TJSONObject;      WriteLn('  ', line.Strings['sku'], ' x', line.Integers['qty']);      total := total + line.Integers['qty'] * line.Integers['cents'];    end;    reply := TJSONObject.Create(['order', order.Integers['id'], 'status', 'confirmed']);    try      reply.Add('total_cents', total);      reply.Add('tags', TJSONArray.Create(['paid', 'gift']));  // reply owns it now      WriteLn(reply.AsJSON);    finally      reply.Free;  // frees everything inside too    end;  finally    order.Free;  end;end.

Output · fpc main.pas && ./main

Order 1042 for Lucia Romero
  MUG-01 x2
  TEA-12 x1
{ "order" : 1042, "status" : "confirmed", "total_cents" : 2995, "tags" : ["paid", "gift"] }

Key points

  • GetJSON turns text into a tree of JSON objects.
  • Integers[...], Strings[...] and Arrays[...] read by name and type.
  • FindPath('a.b') goes down several levels at once.
  • TJSONObject.Create([...]) and Add build JSON; AsJSON writes it.
  • Freeing the root frees everything inside it.

Exercise

Add a shipping object to the reply with the customer's city (order.FindPath('customer.city').AsString) and an express field set to True.