Handling JSON data in Ada

As a beginner in Ada Language, after the first contact and the step-by-step tutorials where you begin with a Hello World and start to learn the basic features of the language (You can see my post here), it’s time to learn how to deal with things more “close” to the real life.

I was so curious to know how Ada deal with JSON, and try to find out some tutorials. Then the first two are:

  • Ada Core, the site where you can download GNAT Programming Studio
  • Rosetta Code, a site where “The idea is to present solutions to the same task in as many different languages as possible”

I decided try the Rosetta Code example, to be a bit more complete.

So, let’s go to step-by-step

First, start the GPS, and click on “Create New Project”

Now choose the Template: Simple Ada Project.

In the next screen, confirm the Directory where you want to deploy your project and choose the Project Name and the Main Name.

The Main name is the name of procedure will be first called, as we’ll see shortly.

And you have a fresh screen ready to program. You can see the name of Procedure is Json, as you chose in previous step.

I’ll reproduce all steps I did, even when I got some errors. I’ll show here how to solve them.

Let’s copy and paste the code from Rosetta Code site, first option that use GNATCOOL library. If you prefer , you can copy and paste the code below. Is the same.

with Ada.Text_IO;
with GNATCOLL.JSON;

procedure JSON_Test is
use Ada.Text_IO;
use GNATCOLL.JSON;

JSON_String : constant String := "{""name"":""Pingu"",""born"":1986}";

Penguin : JSON_Value := Create_Object;
Parents : JSON_Array;
begin
Penguin.Set_Field (Field_Name => "name",
Field => "Linux");

Penguin.Set_Field (Field_Name => "born",
Field => 1992);

Append (Parents, Create ("Linus Torvalds"));
Append (Parents, Create ("Alan Cox"));
Append (Parents, Create ("Greg Kroah-Hartman"));

Penguin.Set_Field (Field_Name => "parents",
Field => Parents);

Put_Line (Penguin.Write);

Penguin := Read (JSON_String, "json.errors");

Penguin.Set_Field (Field_Name => "born",
Field => 1986);

Parents := Empty_Array;
Append (Parents, Create ("Otmar Gutmann"));
Append (Parents, Create ("Silvio Mazzola"));

Penguin.Set_Field (Field_Name => "parents",
Field => Parents);

Put_Line (Penguin.Write);
end JSON_Test;

Click the Button “Build and Run”

We get the first error and warning, as you could see in the two bottom windows

Let’s start solving the warning.

json.adb:4:11: warning: file name does not match unit name, should be "json_test.adb"

The problem is we call the Main Name as “Json”, and when we copy and paste the code from Rosetta Code, the name is JSON_Test. To solve, just change the procedure name to Json on lines 4 and 41:

4   procedure JSON is
...
...
...
40 Put_Line (Penguin.Write);
41 end JSON;

The error:

json.adb:2:06: file "gnatcoll.ads" not found

The GPS install the library GNATCOLL, but you need to inform the project you will use it. To do this, from Project Explorer, right-click Click and go to Project → Properties:

In the Properties window, select Dependencies, and Drag-and-drop gnatcool to the left how you can see in the image below:

Click on Save button, and you’ll see the GnatCool library on the project tree:

Let’s try Build and Run again. But…

In the right bottom window, GPS allow you click on error to go directly to gnatcool-json.ads file to try to figure out what is the problem. So, let’s do this:

In Ada, is possible use a Function Overloading, functions with same name where you could vary the arguments. Is supposed the compiler can choose the correct function, but in this case, the compiler didn’t understand if the parameter is Integer or Long Integer. Remember Ada is a strongly typed language!

To solve this lets use type casting. (Thanks to Keith Thompson from Ada Email group)

Penguin.Set_Field (Field_Name => "born",
Field => Integer'(1992));

Append (Parents, Create ("Linus Torvalds"));
Append (Parents, Create ("Alan Cox"));
Append (Parents, Create ("Greg Kroah-Hartman"));

Penguin.Set_Field (Field_Name => "parents",
Field => Parents);

Put_Line (Penguin.Write);

Penguin := Read (JSON_String, "json.errors");

Penguin.Set_Field (Field_Name => "born",
Field => Integer'(1986));

Click on Build and Run… and SUCCESS!!

Understanding the code

Now I suggest you analyse the code line-by-line.

The code is divided in two blocks: the first one, the JSON object is created from the scratch with variables Penguin of type JSON_Value and Parents of type JSON_Array

  1. First Block of code

The two first commands create fields "name" and "born"

   Penguin.Set_Field (Field_Name => "name", 
Field => "Linux");

Penguin.Set_Field (Field_Name => "born",
Field => Integer'(1992))

The next step is create an Array:

   Append (Parents, Create ("Linus Torvalds"));
Append (Parents, Create ("Alan Cox"));
Append (Parents, Create ("Greg Kroah-Hartman"));

And create another field named "parents" where the content is the Array

Penguin.Set_Field (Field_Name => "parents",
Field => Parents);

To show the result, Put_Line command is used

Put_Line (Penguin.Write);

2. Second Block

In this block the program read a String variable named JSON_String where the content is a JSON structure:

JSON_String : constant String := "{""name"":""Pingu"",""born"":1986}";

To read the string into a JSON_Value variable:

Penguin := Read (JSON_String, "json.errors");

Now, Penguin variable have the JSON:

{
"name": "Pingu",
"born": 1986
}

The next instruction update the field born. In the original code, they use the same value. I suggest you try another one to verify.

   Penguin.Set_Field (Field_Name => "born",
Field => Integer'(1987));

Now, empty the variable Parents and create new entries, and finally show the JSON content.

Parents := Empty_Array;
Append (Parents, Create ("Otmar Gutmann"));
Append (Parents, Create ("Silvio Mazzola"));

Penguin.Set_Field (Field_Name => "parents",
Field => Parents);

Put_Line (Penguin.Write);

It’s time to explore

If you are a beginner like me, I suggest you use the great features of GPS, using right click to see declarations of each variable type, explore the file gnatcool-json.ads, change the values, try use another types, etc.

I hope you enjoy and let’s move on studying Ada Language!