RPG Example reading JSON using YAJL from IFS


Jun 02

Decode JSON webservice reply data (already stored in IFS) using YAJL

This reads 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); 
 DEPARTMENT int(10);

So. lets read it and break it out into fields, which I am just storing 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
   QMHSNDPM( 'CPF9897'
           : '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 = 'Bugger! I couldnt read the IFS file';

*inlr = *on;

So what does this do?

(1) reads the JSON from the input IFS File

(2) Stores a timestamp

(3) decodes the JSON and stores all the values in an array

(4) sends a message to the joblog saying how long it took.

In this case :

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



About the Author

IBM i Software Developer, Digital Dad, AS400 Anarchist, RPG Modernizer, Alpha Nerd and Passionate Eater of Cheese and Biscuits. Nick Litten Dot Com is a mixture of blog posts that can be sometimes serious, frequently playful and probably down-right pointless all in the space of a day. Enjoy your stay, feel free to comment and in the words of the most interesting man in the world: Stay thirsty my friend.