Variable arrays of elements in DFHJS2LS

JSON can contain arrays of varying numbers of elements. In general JSON Schemas that contain varying numbers of elements do not map efficiently into a single high-level language data structure. CICS® uses container-based mappings or inline mappings to handle varying numbers of elements in JSON data.

An array with a varying number of elements is represented in the JSON schema by using the minItems and maxItems keywords in the schema with "type" value of "array":
  • The minItems keyword specifies the minimum number of times that the element can occur. It can have a value of 0 or any positive integer. It defaults to the value 0.
  • The maxItems keyword specifies the maximum number of times that the element can occur. It can have a value of any positive integer greater than or equal to the value of the minItems keyword.
  • If the maxItems keyword is missing it means the array is unbounded.
An optional field can be denoted by a variable array of "maxItems":1. For example, an optional 8 byte string called "component":
"properties":{
   "component": {
      "type":"array",
      "maxItems":1,
      "items": {
         "type": "string",
         "maxLength": 8
      }
   }
},
"required": ["component"]
The same effect can be produced by not including the field name in the "required" keyword value:
"properties":{
   "component": {
      "type": "string",
      "maxLength": 8
   }
}
In general, JSON schemas that contain varying numbers of elements do not map efficiently into a single high-level language data structure. To handle these cases, CICS uses a series of connected data structures that are passed to the application program in a series of containers. These structures are used as input and output from the application:
  • When CICS transforms JSON data to application data, it populates these structures with the application data and the application reads them.
  • When CICS transforms the application data to JSON data, it reads the application data in the structures that have been populated by the application.

The following examples illustrate the format of these data structures. These examples use an array of simple 8-byte fields. However, the model supports arrays of complex data types and arrays of data types that contain other arrays.

Example 1. Fixed number of elements

This example illustrates an element that occurs exactly three times:
"properties":{
   "component": {
      "type": "array",
      "maxItems": 3,
      "minItems": 3,
      "items": {
         "type": "string",
         "maxLength": 8
      }
   }
},
"required": ["component"]

In this example, the number of times that the element occurs is known in advance, so it can be represented as a fixed-length array in a simple COBOL declaration, or the equivalent in other languages.
05 component PIC X(8) OCCURS 3 TIMES

Example 2. Varying number of elements at mapping level 2 and below

This example illustrates a mandatory element that can occur from one to five times:
"properties":{
   "component": {
      "type": "array",
      "maxItems": 5,
      "minItems": 1,
      "items": {
         "type": "string",
         "maxLength": 8
      }
   }
},
"required": ["component"]

The main data structure contains a declaration of two fields. When CICS transforms the JSON data to binary data, the first field component-num contains the number of times that the element appears in the JSON data, and the second field, component-cont, contains the name of a container:
05 component-num PIC S9(9) COMP-5
05 component-cont PIC X(16)
A second data structure contains the declaration of the element itself:
01 DFHJS-component
  02 component PIC X(8)

You must examine the value of component-num, which will contain a value in the range 1 to 5, to find how many times the element occurs. The element contents are in the container named in component-cont; the container holds an array of elements, where each element is mapped by the DFHJS-component data structure.

If minItems="0", or is missing, and maxItems="1", the element is optional. To process the data structure in your application program, you must examine the value of component-num:
  • If it is zero, the message has no component element and the contents of component-cont is undefined.
  • If it is one, the component element is in the container named in component-cont.
The contents of the container are mapped by the DFHJS-component data structure.
Note: If the JSON data consists of a single recurring element, DFHJS2LS generates two language structures. The main language structure contains the number of elements in the array and the name of a container which holds the array of elements. The second language structure maps a single instance of the recurring element.

Example 3. Variable number of elements at mapping level 2.1 and above

At mapping level 2.1 and above, you can use the INLINE-MAXOCCURS-LIMIT parameter in the CICS assistants. The INLINE-MAXOCCURS-LIMIT parameter specifies the way that varying numbers of elements are handled. The mapping options for varying numbers of elements are container-based mapping, described in Example 2. Varying number of elements at mapping level 2 and below, or inline mapping. The value of this parameter can be a positive integer in the range 0 - 32767:
  • The default value of INLINE-MAXOCCURS-LIMIT is 1, which ensures that optional elements are mapped inline.
  • A value of 0 for the INLINE-MAXOCCURS-LIMIT parameter prevents inline mapping.
  • If maxItems is less than or equal to the value of INLINE-MAXOCCURS-LIMIT, inline mapping is used.
  • If maxItems is greater than the value of INLINE-MAXOCCURS-LIMIT, container-based mapping is used.
Mapping varying numbers of elements inline results in the generation of both an array, as happens with the fixed occurrence example above, and a counter. The component-num field indicates how many instances of the element are present, and these are pointed to by the array. For the example shown in Example 2. Varying number of elements at mapping level 2 and below, when INLINE-MAXOCCURS-LIMIT is less than or equal to 5, the generated data structure is like this:
05 component-num PIC S9(9) COMP-5 SYNC. 
05 component OCCURS 5 PIC X(8).
The first field, component-num, is identical to the output for the container-based mapping example in the previous section. The second field contains an array of length 5 which is large enough to contain the maximum number of elements that can be generated.

Inline mapping differs from container-based mapping, which stores the number of occurrences of the element and the name of the container where the data is placed, because it stores all the data in the current container. Storing the data in the current container will generally improve performance and make inline mapping preferable.

Example 4. Nested variable arrays

Complex JSON schemas can contain variable recurring elements, which in turn contain variable recurring elements. In this case, the structure described extends beyond the two levels described in the examples.

This example illustrates an optional element called "component2" that is nested in a mandatory element called "component1", where the mandatory element can occur from one to five times:
"properties":{
   "component1": {
      "type": "array",
      "maxItems": 5,
      "minItems": 1,
      "items": {
         "type": "object",
         "properties":{
            "component2":{
               "type": "string",
               "maxLength": 8
            }
         },
      "required": ["component2"]
      }
   },
"required": ["component1"]
The top-level data structure is exactly the same as in the previous examples:
05 component1-num PIC S9(9) COMP-5
05 component1-cont PIC X(16)
However, the second data structure contains these elements:
01 DFHJS-component1
  02 component2-num PIC S9(9) COMP-5
  02 component2-cont PIC X(16)
A third-level structure contains these elements:
01 DFHJS-component2
  02 component2 PIC X(8)

The number of occurrences of the outermost element "component1" is in component1-num.

The container named in component1-cont contains an array with that number of instances of the second data structure DFHJS-component1.

Each instance of component2-cont names a different container, each of which contains the data structure mapped by the third-level structure DFHJS-component2.

To illustrate this structure, consider the fragment of JSON data that matches the example:
{"component1": 
   [ 
      {
         "component2": "string1"
      },
      {
         "component2": "string2"
      },
   ]
}
"component1" occurs three times. The first two contain an instance of "component2"; the third instance does not.
In the top-level data structure, component1-num contains a value of 3. The container named in component1-cont has three instances of DFHJS-component1:
  1. In the first, component2-num has a value of 1, and the container named in component2-cont holds string1.
  2. In the second, component2-num has a value of 1, and the container named in component2-cont holds string2.
  3. In the third, component2-num has a value of 0, and the contents of component2-cont are undefined.
In this instance, the complete data structure is represented by four containers in all:
  • The root data structure in container DFHJS-DATA.
  • The container named in component1-cont.
  • Two containers named in the first two instances of component2-cont.

Optional structures and the required keyword

Data structures are defined by the JSON Schema "type" of "object". The schemas relate field names to individual types using the object provided by the "properties" keyword. The requirement for these fields to be part of the JSON data described by the JSON Schema is controlled by the array provided by the "required" keyword. This array lists all the field names that must be present in the JSON data. Optional fields are therefore represented by their absence from this array, or as the array is not allowed to be empty, the absence of the "required" keyword. In this case, all fields are optional.

Optional fields are treated as a variable array of 0 or 1 elements. This adds an additional field with the suffix "-num" appended to the element name. If the total length is more than 28 characters, the element name is truncated. At run time this will be non-zero to indicate the value was present in the JSON data and zero if it was not.

This example shows two fields, one required called "required-structure" and the other one optional called "optional-structure" :
{
   "type": "object", 
   "properties":  {
      "required-structure": {
         "type":"string",
         "maxLength": 8
      },
      "optional-structure": {
         "type":"string",
         "maxLength": 8
      }
   },
   "required": [
      "required-structure"
   ]
}
The generated COBOL structure shows both fields, but the second is preceded by "optional-structure-num" which is an integer count of the elements, with 0 representing none and 1 that it is present. The value is set to indicate whether the "optional-structure" contains valid data or not.
03 OutputData.
             06 required-structure            PIC X(8). 
             06 optional-structure-num        PIC S9(9) COMP-5 SYNC. 
             06 optional-structure            PIC X(8).