For a toy project, I wanted to parse some JSON with Ada.
A search in Alire crates suggested me to use json-ada. I used it, it seemed to work well, but as stated on the github page of the project, ‘Unicode may not be supported yet’ (as JSON text are required to be Unicode, this choice seems weird to me). In fact, it just doesn’t work with Unicode and I needed it…
Then I found GNATCOLL.Json. The library seemed quite similar to json-ada in its use and seemed to support UTF-8 encoded strings. At least, they were using UTF8_String, UTF8_Unbounded_String and UTF8_XString types from GNATCOLL.Strings. So I switched to it. It seemed to work well, but then I realised that I could only read JSON from String or Unbounded_String. Maybe I miss something (strings in Ada are such a mess), but I still don’t understand how to use a wide_string or wide_wide_string as input…
Then I found VSS.Json. It seems to be Unicode compatible. I didn’t switched for the moment as it’s quite different to use. But the last release is one year ago and there are changes in the API pending in master. So I would also have to change my code for the next release of VSS.
Am I missing some better JSON library? What are you using?
It has unicode conversions. The reason I suggest this is you could take the original JSON-Ada library and change the top level package to use the UXStrings main string type (UXString) instead of the standard String type.
with UXStrings;
package JSON is
subtype String is UXStrings.UXString;
end JSON;
That’ll globally change all the string types in the JSON library to UXStrings, which is unicode compatible. At that point you may have to doctor any lines with string or character constants to call the conversion functions (To_Unicode, From_Unicode for example). You may also have to remove any “Pure” pragmas in the packags as well as I had to remove it from the top level to support UXStrings.
It’s not out of the box, but if you like the JSON-Ada api, it might be worth playing around with.
If you want to use VSS - just clone repository and use it. I don’t known is there any plans to do official release, except it will be necessary for GNATstudio or ALS release, or someone will want to update Alire crate.
Thank you for the suggestion. However, there are a lot of character comparison with Latin_1 in JSON-Ada. I think I will go the VSS route. My main goal is not to write a JSON parser and it’s not as if I had a large code base to switch.
And if I’m not satisfied with VSS, I’ll try ASAP-JSON. I didn’t knew there was a competitor for alire.
I’m currently using VSS with unicode to parse json. The catch is that unlike json-ada which automatically parses the whole json structure for you, you need to build out exactly what you’re expecting in VSS, you’re basically coding the parser by hand.
I found documentation on VSS to be lacking, and kind of just figured out how to do this stuff by reading source files, so maybe this will help: I’m working on a library to parse Simplefin JSON structures in Ada; I just published the code on github (but don’t use it- it’s not in prerelease yet):
As you can see in the repo, I just used alire via alr with vss and it brought in VSS for me automatically. I only use alire for my coding. The actual parsers are located in simplefin-parsers.ads and simplefin-parsers.adb.
procedure Read_Transaction
(Reader : in out VSS.JSON.Pull_Readers.JSON_Pull_Reader'Class;
Item : out Simplefin.Types.Transaction;
Cur : Cashe.Currency_Handling.Currency_Data;
Success : in out Boolean) is
begin
while Success loop
case Reader.Read_Next is
-- Start of the next account object
when VSS.JSON.Pull_Readers.Key_Name =>
if Reader.Key_Name = "id" then
case Reader.Read_Next is
when VSS.JSON.Pull_Readers.String_Value =>
Item.Id := Reader.String_Value;
when others =>
Success := False;
end case;
elsif Reader.Key_Name = "posted" then
case Reader.Read_Next is
when VSS.JSON.Pull_Readers.Number_Value =>
Item.Posted :=
Ada.Calendar.Conversions.To_Ada_Time
(Interfaces.C.long
(VSS.JSON.As_Integer (Reader.Number_Value)));
when others =>
Success := False;
end case;
elsif Reader.Key_Name = "amount" then
case Reader.Read_Next is
when VSS.JSON.Pull_Readers.String_Value =>
declare
use Cashe;
use Cashe.Money_Handling;
D : Decimal;
begin
Read_Decimal (Reader.String_Value, D, Success);
if Success then
Item.Amount := From_Major (D, Cur);
end if;
end;
when others =>
Success := False;
end case;
elsif Reader.Key_Name = "description" then
case Reader.Read_Next is
when VSS.JSON.Pull_Readers.String_Value =>
Item.Description := Reader.String_Value;
when others =>
Success := False;
end case;
elsif Reader.Key_Name = "memo" then
case Reader.Read_Next is
when VSS.JSON.Pull_Readers.String_Value =>
Item.Memo := Reader.String_Value;
when others =>
Success := False;
end case;
elsif Reader.Key_Name = "payee" then
case Reader.Read_Next is
when VSS.JSON.Pull_Readers.String_Value =>
Item.Payee := Reader.String_Value;
when others =>
Success := False;
end case;
elsif Reader.Key_Name = "pending" then
case Reader.Read_Next is
when VSS.JSON.Pull_Readers.Boolean_Value =>
Item.Pending := Reader.Boolean_Value;
when others =>
Success := False;
end case;
elsif Reader.Key_Name = "extra" then
-- Todo
Skip_Object (Reader);
else
Success := False;
end if;
when VSS.JSON.Pull_Readers.Start_Object =>
null;
when VSS.JSON.Pull_Readers.End_Object =>
exit;
when others =>
Success := False;
end case;
end loop;
end Read_Transaction;
You can check out the source for other things I’m doing like reading json arrays or other such stuff.
Yes, I succeeded to make gnatcoll work. Just had to do the right encode/decode before and after.
But xmlada dependency pulled by gnatcoll is not working well with alire. Each time I build my project, xmlada needs some reconfiguration. On my linux (old) personal desktop, it is fast (seconds). But on my windows (recent) work laptop, it is really slow (minutes!) and annoying.