Example 4
This example program demonstrates the basic structure of an RPG program utilizing RXS to compose a JSON string with repeating elements.
**FREE
Ctl-Opt ActGrp(*Caller) BndDir('RXSBND') Option(*NoDebugIO) ExtBinInt(*Yes) DecEdit('0.')
Text('Ex. 4 - JSON Compose');
/COPY QRPGLECPY,RXSCB
Dcl-Ds PutStmfDS LikeDS(RXS_PutStmfDS_t);
Dcl-Ds CreateJsonDS LikeDS(RXS_CreateJsonDS_t);
Dcl-Ds RootDS LikeDS(RXS_JsonStructureDS_t);
Dcl-Ds UsersArrayDS LikeDS(RXS_JsonStructureDS_t);
Dcl-Ds UserObjectDS LikeDS(RXS_JsonStructureDS_t);
Dcl-Ds JsonArrayDS LikeDS(RXS_JsonStructureDS_t);
Dcl-S i Uns(3);
Dcl-S JSON Like(RXS_Var64Kv_t);
Dcl-S dateVal Char(10);
monitor;
// Use RXS_ResetDS to ensure that the CreateJsonDS data structures is
// properly initialized. We don't have to use this on the various
// RXS_JsonStructureDS_t structures because the other RXS subprocedures
// will handle those for us.
RXS_ResetDS( CreateJsonDS : RXS_DS_TYPE_CREATEJSON );
// Create root JSON Object
CreateJsonDS.Prettify = RXS_JSON_TRUE;
CreateJsonDS.JsonStructureType = RXS_JSON_STRUCTURE_OBJECT;
RootDS = RXS_CreateJson( CreateJsonDS );
// Create JSON Array named users & attach to RootDS
UsersArrayDS = RXS_ComposeJsonArray( 'users' : RootDS );
// Loop through and add multiple objects to a JSON Array named "users".
// Typically you'd want to use a normal RPG database read loop here
// instead of a 'for' loop.
for i = 1 to 3;
// Create object for a customer, attach to array
UserObjectDS = RXS_ComposeJsonObject( *Omit : UsersArrayDS );
// Add various character fields & data to the users object we just created.
RXS_ComposeJsonString( 'firstName' : 'First Name' : UserObjectDS );
RXS_ComposeJsonString( 'lastName' : 'Last Name' : UserObjectDS );
RXS_ComposeJsonString( 'email' : 'Email Address' : UserObjectDS );
RXS_ComposeJsonString( 'username' : 'Username' : UserObjectDS );
RXS_ComposeJsonString( 'password' : 'Password' : UserObjectDS );
endfor;
// The next few parts of this JSON structure are a series of arrays.
// We could define D spec data structure for each if we wanted to,
// but it's not required. We still need to ensure we're attaching
// them to our root object RootDS though.
JsonArrayDS = RXS_ComposeJsonArray( 'requiredCourseIds' : RootDS );
// Again, you'd probably be reading one or more child records out of
// a physical file here with an RPG read loop instead of a 'for' loop.
for i = 1 to 10;
// Note that the key difference between a JSON Object and a
// JSON Array is that a JSON Object can contain one or more
// name/value pairs (and the values can be of any type - a child
// JSON Object, a JSON Array, or just a plain string/int/etc value)
// A JSON Array can hold one or more values ONLY. The values a JSON
// Array holds must all be of the same type (e.g. all JSON Object,
// all plain string/int/etc values, or even another JSON Array),
// and cannot have a name associated with them.
// The easiest way to think about these two is that a JSON Object
// is like an RPG data structure, whereas a JSON Array is like
// an RPG data structure or normal field but with the Dim keyword
// used.
// Because we can't name the values we're putting in our array, the
// second parm for RXS_ComposeJsonNumber() must be *OMIT.
// We're using RXS_ComposeJsonNumber() to ensure that in the JSON
// the values we're passing show up as numeric (e.g. not wrapped
// in double quotes)
// To handle large numbers effectively, RXS_ComposeJsonNumber()
// actually accepts a character representation of a number as
// opposed to an RPG numeric field type.
RXS_ComposeJsonNumber( *Omit : %Char(i) : JsonArrayDS );
endfor;
// We're re-using the JsonArrayDS structure for the next few arrays
// as they are very simple arrays but the whole process is otherwise
// the same as for requiredCourseIds[]
JsonArrayDS = RXS_ComposeJsonArray( 'courseIds' : RootDS );
for i = 1 to 10;
RXS_ComposeJsonNumber( *Omit : %Char(i * 2) : JsonArrayDS );
endfor;
JsonArrayDS = RXS_ComposeJsonArray( 'seriesIds' : RootDS );
for i = 1 to 10;
RXS_ComposeJsonNumber( *Omit : %Char(i * 3) : JsonArrayDS );
endfor;
JsonArrayDS = RXS_ComposeJsonArray( 'groupIds' : RootDS );
for i = 1 to 10;
RXS_ComposeJsonNumber( *Omit : %Char(i * 4) : JsonArrayDS );
endfor;
// Next, we need to add a date named datestamp to our RootDS.
// JSON doesn't have a 'date' data type, so we add this as a
// string and do whatever formatting the API we're calling requires.
// In this case we're using *ISO YYYY-MM-DD date format
dateVal = %Char( %Date() : *ISO );
RXS_ComposeJsonString( 'datestamp' : dateVal : RootDS );
// Next we're going to add JSON boolean and null values
RXS_ComposeJsonBoolean( 'processed' : RXS_JSON_TRUE : RootDS );
RXS_ComposeJsonNull( 'referenceId' : RootDS );
// Now that we've added all of the data fields to our JSON object,
// let's generate our JSON string
JSON = RXS_GetJsonString( CreateJsonDS );
// Dump JSON to file
RXS_ResetDS( PutStmfDS : RXS_DS_TYPE_PUTSTMF );
PutStmfDS.Stmf = '/tmp/json_excompose1.txt';
RXS_PutStmf( JSON : PutStmfDS );
on-error;
RXS_DestroyJson( CreateJsonDS );
endmon;
// Always call RXS_DestroyJson() to free up the memory we used.
// This must be called AFTER we retrieve our string
// with RXS_GetJsonString(), or there will be nothing to retrieve!
// It is enough to just call RXS_DestroyJson() on the CreateJsonDS data
// structure - it will free the memory used by all of the child
// data structures that were linked to it as well.
RXS_DestroyJson( CreateJsonDS );
*INLR = *ON;
return;
H DFTACTGRP(*NO) ACTGRP(*CALLER) BNDDIR('RXSBND') OPTION(*NODEBUGIO)
H EXTBININT(*YES) DECEDIT('0.')
H TEXT('Fixed Format Ex. 4 - JSON Compose')
/COPY QRPGLECPY,RXSCB
D PutStmfDS DS LikeDS(RXS_PutStmfDS_t)
D CreateJsonDS DS LikeDS(RXS_CreateJsonDS_t)
D RootDS DS LikeDS(RXS_JsonStructureDS_t)
D UsersArrayDS DS LikeDS(RXS_JsonStructureDS_t)
D UserObjectDS DS LikeDS(RXS_JsonStructureDS_t)
D JsonArrayDS DS LikeDS(RXS_JsonStructureDS_t)
D i S 3U 0
D JSON S Like(RXS_Var64Kv_t)
D dateVal S 10A
/FREE
monitor;
// Use RXS_ResetDS to ensure that the CreateJsonDS data structures is
// properly initialized. We don't have to use this on the various
// RXS_JsonStructureDS_t structures because the other RXS
// subprocedures will handle those for us.
RXS_ResetDS( CreateJsonDS : RXS_DS_TYPE_CREATEJSON );
// Create root JSON Object
CreateJsonDS.Prettify = RXS_JSON_TRUE;
CreateJsonDS.JsonStructureType = RXS_JSON_STRUCTURE_OBJECT;
RootDS = RXS_CreateJson( CreateJsonDS );
// Create JSON Array named users & attach to RootDS
UsersArrayDS = RXS_ComposeJsonArray( 'users' : RootDS );
// Loop through and add multiple objects to the JSON Array named
// "users". Typically you'd want to use a normal RPG database
// read loop here instead of a 'for' loop.
for i = 1 to 3;
// Create object for a customer, attach to array
UserObjectDS = RXS_ComposeJsonObject( *Omit : UsersArrayDS );
// Add various character fields & data to the users object we just
// created.
RXS_ComposeJsonString( 'firstName' : 'First Name' : UserObjectDS );
RXS_ComposeJsonString( 'lastName' : 'Last Name' : UserObjectDS );
RXS_ComposeJsonString( 'email' : 'Email Address' : UserObjectDS );
RXS_ComposeJsonString( 'username' : 'Username' : UserObjectDS );
RXS_ComposeJsonString( 'password' : 'Password' : UserObjectDS );
endfor;
// The next few parts of this JSON structure are a series of arrays.
// We could define D spec data structure for each if we wanted to,
// but it's not required. We still need to ensure we're attaching
// them to our root object RootDS though.
JsonArrayDS = RXS_ComposeJsonArray( 'requiredCourseIds' : RootDS );
// Again, you'd probably be reading one or more child records out of
// a physical file here with an RPG read loop instead of a
// 'for' loop.
for i = 1 to 10;
// Note that the key difference between a JSON Object and a
// JSON Array is that a JSON Object can contain one or more
// name/value pairs (and the values can be of any type - a child
// JSON Object, a JSON Array, or just a plain string/int/etc value)
// A JSON Array can hold one or more values ONLY. The values a JSON
// Array holds must all be of the same type (e.g. all JSON Object,
// all plain string/int/etc values, or even another JSON Array),
// and cannot have a name associated with them.
// The easiest way to think about these two is that a JSON Object
// is like an RPG data structure, whereas a JSON Array is like
// an RPG data structure or normal field but with the Dim keyword
// used.
// Because we can't name the values we're putting in our array, the
// second parm for RXS_ComposeJsonNumber() must be *OMIT.
// We're using RXS_ComposeJsonNumber() to ensure that in the JSON
// the values we're passing show up as numeric (e.g. not wrapped
// in double quotes)
// To handle large numbers effectively, RXS_ComposeJsonNumber()
// actually accepts a character representation of a number as
// opposed to an RPG numeric field type.
RXS_ComposeJsonNumber( *Omit : %Char(i) : JsonArrayDS );
endfor;
// We're re-using the GenericArrayDS structure for the next few arrays
// as they are very simple arrays but the whole process is otherwise
// the same as for requiredCourseIds[]
JsonArrayDS = RXS_ComposeJsonArray( 'courseIds' : RootDS );
for i = 1 to 10;
RXS_ComposeJsonNumber( *Omit : %Char(i * 2) : JsonArrayDS );
endfor;
JsonArrayDS = RXS_ComposeJsonArray( 'seriesIds' : RootDS );
for i = 1 to 10;
RXS_ComposeJsonNumber( *Omit : %Char(i * 3) : JsonArrayDS );
endfor;
JsonArrayDS = RXS_ComposeJsonArray( 'groupIds' : RootDS );
for i = 1 to 10;
RXS_ComposeJsonNumber( *Omit : %Char(i * 4) : JsonArrayDS );
endfor;
// Next, we need to add a date named datestamp to our RootDS.
// JSON doesn't have a 'date' data type, so we add this as a
// string and do whatever formatting the API we're calling requires.
// In this case we're using a YYYY-MM-DD date format
dateVal = %Char( %Date() : *ISO );
RXS_ComposeJsonString( 'datestamp' : dateVal : RootDS );
// Next we're going to add JSON boolean and null values
RXS_ComposeJsonBoolean( 'processed' : RXS_JSON_TRUE : RootDS );
RXS_ComposeJsonNull( 'referenceId' : RootDS );
// Now that we've added all of the data fields to our JSON object,
// let's generate our JSON string
JSON = RXS_GetJsonString( CreateJsonDS );
// Dump JSON to file
RXS_ResetDS( PutStmfDS : RXS_DS_TYPE_PUTSTMF );
PutStmfDS.Stmf = '/tmp/json_excompose1.txt';
RXS_PutStmf( JSON : PutStmfDS );
on-error;
RXS_DestroyJson( CreateJsonDS );
endmon;
// Always call RXS_DestroyJson() to free up the memory we used.
// This must be called AFTER we retrieve our string
// with RXS_GetJsonString(), or there will be nothing to retrieve!
// It is enough to just call RXS_DestroyJson() on the CreateJsonDS data
// structure - it will free the memory used by all of the child
// data structures that were linked to it as well.
RXS_DestroyJson( CreateJsonDS );
*INLR = *ON;
return;
/END-FREE