Example RPG to decode JSON from IFS using YAJL

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 and reports on time taken to perform decode.

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);

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…

/TITLE JSON_TABLE Decode JSON using Y.A.J.L. - Proof of Concept

// ------------------------------------------------------
// Create as a Module and bind into ILE program
// JSNIFSYAJL.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 suitable
// for display from a program debugger.
// Check input data -
// DSPLNK OBJ( ** value from IFSFilename ** )
// 07/17/2017 nick.litten V1.00

ctl-opt dftactgrp(*no) actgrp('LITTENN')
bnddir('YAJL') alwnull(*inputonly)
datfmt(*ISO) decedit('0.')
copyright('| JSNIFSYAJL 1.0 06/27/2017 Use YAJL to read JSON from IFS and Parse.');

/include yajl_h

// IFS file with JSON code that we will be reading and decoding
dcl-c ifsFilename

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

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

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 lastElement int(10) inz;
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

// Parms for logging-text being sent back into program message queue
dcl-pr QMHSNDPM extpgm('QMHSNDPM');
  *n char(7) const; // MsgID
  *n char(20) const; // MsgFile
  *n char(32767) const options(*varsize); // MsgData
  *n int(10) const; // MsgDtaLen
  *n char(10) const; // MsgType
  *n char(10) const; // StackEntry
  *n int(10) const; // StackCount
  *n char(4); // MsgKey
  *n char(32767) options(*varsize); // ErrorCode

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

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

/Title [---------- MAINLINE ---------- ]


// Load JSON in from the IFS file using YAJL
docNode = yajl_stmf_load_tree( 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 );

  lastElement = Count;

  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: '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);



 // Set Ending timestamps and calculate runtime

 joblogMsg = 'JSNIFSYAJL Completed with ' +
       %char(lastElement) +
       ' elements. Total runtime:' +
       %char(%diff(endTimeStamp:strTimeStamp:*mseconds)) +
       ' YAJL DECODE only:' +
       %char(%diff(endTimeStamp:strJsonTimeStamp:*mseconds)) ;

 // stick that message into the joblog so we
 // can clearly see the runtime
        : 'QCPFMSG *LIBL'
        : joblogMsg
        : %len(%trimr(joblogMsg))
        : '*DIAG'
        : '*'
        : 0
        : MsgKey
        : ErrorCode );

 // 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';

*inlr = *on;

So what does this do?

  • Reads the JSON from the input IFS File
  • Stores a timestamp
  • Decodes the JSON and stores all the values in an array
  • Sends a message to the joblog saying how long it took

In this case :

JSNIFSYAJL Completed with 91 elements. Total runtime:11000 YAJL DECODE only:4000

Easy Peasy right?

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