Need help with your JSON?

Try our JSON Formatter tool to automatically identify and fix syntax errors in your JSON. JSON Formatter tool

Ada Language JSON Libraries and Format Converters

JSON (JavaScript Object Notation) has become a ubiquitous data interchange format across various programming ecosystems. For Ada developers, interacting with web services, configuration files, or external systems often necessitates reading and writing JSON data. While Ada is known for its strong typing and safety features, it also has libraries available to handle the dynamic nature of JSON effectively.

This page explores the landscape of JSON processing in Ada, focusing on available libraries and common patterns for parsing JSON into Ada data structures and generating JSON from Ada data.

Key Ada JSON Libraries

Several libraries cater to JSON handling in Ada, each with its strengths and target environments. The most prominent ones include:

AWA.JSON

Part of the Ada Web Applications (AWA) framework, AWA.JSON is a mature and widely used library. It provides comprehensive capabilities for parsing, generating, and manipulating JSON documents.

  • Representation: Uses a tagged type hierarchy (JSON_Value, JSON_Object, JSON_Array, etc.) to represent JSON structures in memory.
  • Parsing: Offers SAX-like (event-based) and DOM-like (in-memory tree) parsing approaches.
  • Generating: Provides procedures to build JSON structures programmatically and render them as strings.
  • Integration: Designed to integrate well within the AWA framework but can be used independently.
  • Typing: Strong emphasis on type safety when extracting values (e.g., `Get_Field_String`, `Get_Field_Integer`).

JSON-Ada

JSON-Ada is another popular choice, developed by AdaCore. It offers a simpler API compared to AWA.JSON, focusing on core parsing and generation.

  • Representation: Also uses a tagged type (Json_Value) to represent JSON values.
  • Parsing: Primarily provides a DOM-like parsing interface.
  • Generating: Supports building JSON structures and serializing them.
  • Simplicity: Often perceived as having a more straightforward API for basic tasks.

Other Options / Standard Ada

While not standard library features, other community projects might exist. It's worth checking community forums and repositories. Generally, for robust JSON support, relying on established libraries like AWA.JSON or JSON-Ada is recommended.

Working with JSON: Examples

Let's look at simplified examples using a hypothetical library (drawing concepts from AWA.JSON and JSON-Ada) to illustrate common tasks: parsing and generation.

Parsing JSON

Converting a JSON string into an in-memory Ada representation.

Ada Example: Parsing a JSON Object

with Ada.Text_IO; use Ada.Text_IO;
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
with Json_Library.Parser;   -- Hypothetical parser package
with Json_Library.Values;   -- Hypothetical values package
with Json_Library.Elements; -- Hypothetical element access

procedure Parse_Example is
   JSON_Input : Unbounded_String := To_Unbounded_String (
      "{" & ASCII.LF &
      "  ""name"": ""Ada Lovelace""," & ASCII.LF &
      "  ""age"": 201," & ASCII.LF &
      "  ""isStudent"": false," & ASCII.LF &
      "  ""courses"": [""Mathematics"", ""Computer Science""]" & ASCII.LF &
      "}"
   );

   Root_Value : aliased Json_Library.Values.Json_Value_Access; -- Pointer to the parsed value
   Name       : Unbounded_String;
   Age        : Integer;
   Is_Student : Boolean;
   Courses    : aliased Json_Library.Values.Json_Value_Access; -- Pointer to the courses array
begin
   -- Parse the JSON string
   Root_Value := Json_Library.Parser.Parse (JSON_Input);

   -- Assuming the root is an object, access fields
   if Root_Value.Is_Object then
      declare
         Root_Object : constant Json_Library.Values.Json_Object_Access :=
            Root_Value.Get_Object; -- Type-safe access

         Name_Value : aliased Json_Library.Values.Json_Value_Access;
         Age_Value  : aliased Json_Library.Values.Json_Value_Access;
         Is_Student_Value : aliased Json_Library.Values.Json_Value_Access;

      begin
         -- Access individual fields by name
         Name_Value       := Root_Object.Get_Field ("name");
         Age_Value        := Root_Object.Get_Field ("age");
         Is_Student_Value := Root_Object.Get_Field ("isStudent");
         Courses          := Root_Object.Get_Field ("courses");

         -- Extract values with type checking
         if Name_Value.Is_String then
            Name := Name_Value.Get_String;
            Put_Line ("Name: " & To_String (Name));
         end if;

         if Age_Value.Is_Integer then
            Age := Age_Value.Get_Integer;
            Put_Line ("Age: " & Integer'Image (Age));
         end if;

         if Is_Student_Value.Is_Boolean then
            Is_Student := Is_Student_Value.Get_Boolean;
            Put_Line ("Is Student: " & Boolean'Image (Is_Student));
         end if;

         if Courses.Is_Array then
            Put_Line ("Courses:");
            declare
               Course_Array : constant Json_Library.Values.Json_Array_Access :=
                  Courses.Get_Array;
            begin
               for I in 1 .. Course_Array.Length loop
                  declare
                     Course_Value : aliased Json_Library.Values.Json_Value_Access :=
                        Course_Array.Get_Element (I);
                  begin
                     if Course_Value.Is_String then
                        Put_Line ("- " & To_String (Course_Value.Get_String));
                     end if;
                  end;
               end loop;
            end;
         end if;

      exception
         when Json_Library.Elements.Name_Error =>
            Put_Line ("Error: Field not found or wrong type.");
         when others =>
            Put_Line ("An error occurred during access.");
      end;
   else
      Put_Line ("Error: JSON root is not an object.");
   end if;

exception
   when Json_Library.Parser.Parse_Error =>
      Put_Line ("Error: Invalid JSON format.");
   when others =>
      Put_Line ("An unexpected error occurred.");
end Parse_Example;

Note: The package names (Json_Library, etc.) are illustrative and depend on the specific library used (e.g., AWA.JSON.Parsers, AWA.JSON.Values, or packages from JSON-Ada). Actual libraries provide similar functionalities but with specific package structures and type names. Error handling is crucial; Ada libraries typically use exceptions.

Generating JSON

Creating a JSON string from Ada data structures or by building the JSON tree programmatically.

Ada Example: Generating a JSON Object

with Ada.Text_IO; use Ada.Text_IO;
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
with Json_Library.Builder; -- Hypothetical builder package
with Json_Library.Values;  -- Hypothetical values package

procedure Generate_Example is
   -- Data to be serialized
   Name       : constant Unbounded_String := To_Unbounded_String ("Grace Hopper");
   Age        : constant Integer := 85;
   Is_Active  : constant Boolean := True;
   Skills     : constant array (1 .. 2) of Unbounded_String :=
      (To_Unbounded_String ("COBOL"), To_Unbounded_String ("Debugging"));

   -- JSON structure built programmatically
   Root_Object : aliased Json_Library.Values.Json_Value_Access; -- Pointer to the root object
   Skills_Array : aliased Json_Library.Values.Json_Value_Access; -- Pointer to the skills array
   JSON_Output : Unbounded_String;

begin
   -- Create a new JSON object
   Root_Object := Json_Library.Builder.New_Object;

   -- Add fields to the object
   Root_Object.Put ("name", Json_Library.Builder.New_String (Name));
   Root_Object.Put ("age",  Json_Library.Builder.New_Integer (Age));
   Root_Object.Put ("isActive", Json_Library.Builder.New_Boolean (Is_Active));

   -- Create a JSON array for skills
   Skills_Array := Json_Library.Builder.New_Array;
   for Skill of Skills loop
      Skills_Array.Append (Json_Library.Builder.New_String (Skill));
   end loop;

   -- Add the skills array to the root object
   Root_Object.Put ("skills", Skills_Array);

   -- Serialize the JSON structure to a string
   JSON_Output := Json_Library.Builder.To_String (Root_Object);

   -- Output the generated JSON
   Put_Line ("Generated JSON:");
   Put_Line (To_String (JSON_Output));

   -- Don't forget to free memory managed by the JSON library if needed (depends on library)

exception
   when others =>
      Put_Line ("An error occurred during generation.");
end Generate_Example;

Note: Again, package names are illustrative. Libraries provide functions like New_Object, New_String, Put, New_Array, Append, and To_String to build and serialize the JSON structure. Memory management (using access types/pointers) is important in Ada; modern libraries often handle this internally or provide explicit cleanup procedures.

JSON and Format Converters

Direct, general-purpose format conversion libraries (e.g., XML to JSON, YAML to JSON) might not be as common or standardized in the Ada ecosystem compared to languages like Python or Java. However, you can achieve format conversion using Ada JSON libraries in several ways:

  • JSON as an Intermediate: Parse the source format (e.g., XML) into a generic, in-memory tree representation, then traverse that tree and build an AWA.JSON or JSON-Ada structure, and finally serialize the JSON structure.
  • Leveraging Existing Parsers: Use an Ada library for the source format (e.g., an XML parser if available), extract data, and then use a JSON library to construct the JSON output.
  • Calling External Tools: For complex or less common formats, it might be pragmatic to call an external command-line tool (written in another language) from your Ada program to perform the conversion.
  • Schema-Based Conversion: If you have schemas for both formats, you might write Ada code that directly maps elements/fields from one structure to the other based on the schema definitions.

Building a robust, general-purpose converter in Ada often means using the existing parsers/generators for each format involved and writing the mapping logic yourself.

Practical Considerations

  • Schema Validation: Ada JSON libraries typically don't include built-in JSON schema validation. You may need to implement checks manually after parsing or use external tools.
  • Performance and Memory: DOM-like parsing (building the whole tree in memory) can be memory-intensive for very large JSON documents. Consider SAX-like parsing if available (like in AWA.JSON) for streaming data.
  • Error Handling: JSON parsing and access can fail due to invalid format, missing fields, or type mismatches. Use Ada's exception handling mechanisms (begin...exception...end blocks) to catch errors gracefully, as shown in the parsing example.
  • Integration with Ada Types: Mapping between generic JSON values and specific Ada record types often requires manual coding. Libraries might offer helper utilities, but it's a common task developers handle.

Choosing a Library

When deciding between libraries like AWA.JSON and JSON-Ada, consider:

  • Project Ecosystem: If you are already using the AWA framework, AWA.JSON is a natural fit.
  • Complexity Needs: For very complex JSON structures or large-scale web applications, AWA.JSON might offer more features (like SAX parsing). For simpler tasks, JSON-Ada might feel more lightweight.
  • API Preference: Review the documentation and choose the API style that best suits your team and project.
  • Community and Support: Both libraries have support from their respective communities (AdaCore for JSON-Ada, the AWA community for AWA.JSON).

Conclusion

Ada provides capable libraries for working with JSON data, primarily through established projects like AWA.JSON and JSON-Ada. While Ada's strong typing means you often need to explicitly handle the mapping between dynamic JSON values and static Ada types, these libraries offer the necessary tools for parsing, generation, and manipulation. Understanding their API and managing potential errors through Ada's robust exception system are key to successfully integrating JSON processing into your Ada applications. For format conversion tasks, using JSON as an intermediate step or leveraging format-specific parsers/generators within Ada are common approaches.

Need help with your JSON?

Try our JSON Formatter tool to automatically identify and fix syntax errors in your JSON. JSON Formatter tool