RPG Example to Read JSON and Decode

Let's use an opensource software tool called YAJL to read the response we just got from our webservice. This response was stored in the IFS for this example.

This code example takes the JSON from the IFS – decodes it using Y.A.J.L is ready for you to add some business logic to do something with that decoded JSON data.

Writing an RPG program to read JSON using YAJL is actually pretty straightforward — I hope this code example helps!

In this case the JSON data is a simple layout that looks like this:

{"users": [{ "userID": "@123", "firstName": "Billy", "lastName": "Bob", "initials": "123", "company": 110, "division": 30, "department": 325, "secProfile": "" }, { "userID": "AAATEMP", "firstName": "Albert", "lastName": "Smith", "initials": "AAA", "company": 110, "division": 1, "department": 1, "secProfile": "" }, { "userID": "AAATEST", "firstName": "Andy", "lastName": "Tester", "initials": "AAA", "company": 110, "division": 1, "department": 530, "secProfile": "AAT" }, { "userID": "AAA3", "firstName": "Fred", "lastName": "Blogs", "initials": "AA3", "company": 110, "division": 1, "department": 1, "secProfile": "AAA" }, { "userID": "AATEST", "firstName": "AA", "lastName": "TEST", "initials": "AAT", "company": 110, "division": 1, "department": 1, "secProfile": "" }, { "userID": "ABB", "firstName": "Abba", "lastName": "Dancing Queen", "initials": "", "company": 110, "division": 1, "department": 1, "secProfile": "" }, { "userID": "BINGBONG", "firstName": "Bing", "lastName": "Bong", "initials": "BB", "company": 110, "division": 2, "department": 2, "secProfile": "" }, { "userID": "LITTENN", "firstName": "Nick", "lastName": "Litten", "initials": "NJL", "company": 1, "division": 1, "department": 123, "secProfile": "Secret Squirrel" }]}

This JSON example contains the values:

USERID varchar(100);
FIRSTNAME varchar(100);
LASTNAME varchar(100);
INITIALS varchar(100);
COMPANY int(10);
DIVISION int(10);
DEPARTMENT int(10);
SECPROFILE varchar(100);

NOTE: In the program example you will notice the variable 'SECPROFILE' is deliberately defined, and loaded, out of sequence in the SQLRPGLE below. This is simply showing you that you can load it in any sequence you like -- you are NOT locked into using the same data sequence as defined in the JSON.

Lets read it and break it out into fields. Then I am just storing these data fields in an array. You could write them to a file just as easily…

**FREE
/TITLE Read from IFS and Decode JSON using Y.A.J.L. - Proof of Concept

// ----------------------------------------------------------
// PROGRAM CREATION OVERRIDES:
//
// Create as a Module and bind into ILE program
//
// IFS2JSNYJL.sqlrpgle (fully /free)
//
// This demonstrates reading JSON data from an IFS file and then
// parsing that JSON to break out the subffields using Y.A.J.L.
// Subfields within the objects are retrieved by their field names.
//
// The JSON data is loaded into a data structure that you
// would then process and do whatever business logic you wanted
// but in our example we will be just proving this works.
//
// ADDLIBLE YAJL
// CRTSQLRPGI OBJ(NICKLITTEN/IFS2JSNYJL)
// SRCSTMF('/home/nicklitten/source/IFS2JSNYJL.sqlrpgle')
// COMMIT(*NONE)
// OBJTYPE(*PGM)
// DBGVIEW(*SOURCE)
// CVTCCSID(*JOB)
//
// ----------------------------------------------------------
// Modification History:
// 2017-07-17 V1 Created
// 2024-09-23 V1.1 Use mainline proc and receive IFS as parm
// ----------------------------------------------------------

ctl-opt
Main(mainline)
pgminfo(*PCML:*MODULE:*DCLCASE)
option(*srcstmt:*nodebugio:*noshowcpy)
decedit('0.')
bnddir('YAJL')
copyright('| IFS2JSNYJL 1.1 09/23/2024 Use YAJL to read JSON from IFS and Parse.');

// include the YAJL magic (update this to be your install location)
/include yajl_h

// declare proc and variables to easily write to joblog
dcl-s joblogMSG varchar(200);
dcl-c joblogCRLF const(x'0d25');
dcl-pr writeJobLog int(10) extproc('Qp0zLprintf');
*n pointer value options(*string); // logMsg
*n pointer value options(*string:*nopass);
*n pointer value options(*string:*nopass);
*n pointer value options(*string:*nopass);
*n pointer value options(*string:*nopass);
*n pointer value options(*string:*nopass);
*n pointer value options(*string:*nopass);
*n pointer value options(*string:*nopass);
*n pointer value options(*string:*nopass);
*n pointer value options(*string:*nopass);
*n pointer value options(*string:*nopass);
end-pr;



// ----------------------------------------------------------
// MAINLINE - Process the incoming webservice payload
// ----------------------------------------------------------
Dcl-Proc mainline;
Dcl-PI mainline;
ifsFilename char(500);
end-pi;

dcl-ds jsonFields qualified template;
USERID varchar(100);
FIRSTNAME varchar(100);
LASTNAME varchar(100);
INITIALS varchar(100);
secProfile varchar(100);
COMPANY int(10);
DIVISION int(10);
DEPARTMENT int(10);
end-ds;

dcl-ds result qualified;
success ind;
errmsg varchar(500);
jsonArray likeds(jsonFields) dim(9999);
end-ds;

dcl-s docNode like(yajl_val);
dcl-s list like(yajl_val);
dcl-s node like(yajl_val);
dcl-s val like(yajl_val);

dcl-s Count int(10);
dcl-s errMsg varchar(500) inz('');

dcl-s strTimeStamp timestamp inz; // start of pgm
dcl-s strJsonTimeStamp timestamp inz; // start of JSON decode logic
dcl-s endTimeStamp timestamp inz; // used to calculate duration

dcl-ds ErrorCode;
BytesProv int(10) inz(0);
BytesAvail int(10) inz(0);
end-ds;

dcl-s joblogMsg char(200);
dcl-s MsgKey char(4);

// Load JSON in from the IFS file using YAJL
docNode = yajl_stmf_load_tree ( %trim(ifsFilename) : errMsg );

// If it loaded then lets decode it:
if errMsg = '';

// Write the JSON *header* level values
node = YAJL_object_find(docNode: 'success');
result.success = YAJL_is_true(node);

node = YAJL_object_find(docNode: 'errmsg');
result.errmsg = YAJL_get_string(node);

list = YAJL_object_find(docNode: 'users');

// Write the JSON *data array* level values
Count = 0;
dow YAJL_ARRAY_LOOP( list: Count: node );

val = YAJL_object_find(node: 'userID');
result.jsonArray(Count).userID = yajl_get_string(val);

val = YAJL_object_find(node: 'firstName');
result.jsonArray(Count).firstName = yajl_get_string(val);

val = YAJL_object_find(node: 'lastName');
result.jsonArray(Count).lastName = yajl_get_string(val);

val = YAJL_object_find(node: 'initials');
result.jsonArray(Count).initials = yajl_get_string(val);

val = YAJL_object_find(node: 'secProfile');
result.jsonArray(Count).secProfile = yajl_get_string(val);

val = YAJL_object_find(node: 'company');
result.jsonArray(Count).company = yajl_get_number(val);

val = YAJL_object_find(node: 'division');
result.jsonArray(Count).division = yajl_get_number(val);

val = YAJL_object_find(node: 'department');
result.jsonArray(Count).department = yajl_get_number(val);

enddo;

yajl_tree_free(docNode);

// At this time all the JSON has been read, decoded and stored
// in the data structure array called 'jsonArray'
// You might add some business logic here to process that array

joblogMsg = 'IFS2JSNYJL Completed with ' + %char(count-1) + ' elements.';

else;

// If unable to load JSON data from the IFS then
// tell the world
result.success = *off;
result.errmsg = 'Aaargh! I couldnt read the IFS file';

// write joblog to see the runtime
joblogMsg = 'IFS2JSNYJL Failed to load IFS - ERRMSG(' + errMsg + ')';

endif;

writeJobLog ( joblogMSG +'%s' : joblogCRLF );

return;

End-Proc;

So what does this do?

  • Reads the JSON from the input IFS File
  • Decodes the JSON and stores all the values in an array
  • Is ready for you to play with 😉

Easy Peasy right?

{"email":"Email address invalid","url":"Website address invalid","required":"Required field missing"}
>