IBM i > DEVELOPER > RPG

An RPGers First Steps with JSON: Consuming JSON data with YAJL

JSON

Time to start the processing. Since this particular JSON document is stored in the IFS we are using the API yajl_stmf_load_tree (D) to load the document identified by the first parameter, into YAJL's document tree. If the load is successful, the API returns the node locator for the root element. If an error were encountered then a message would be placed in the second parameter ( errMsg ). Possible errors include the file being missing, or otherwise inaccessible, or syntax errors encountered when parsing the JSON data.

At (E) we test the error message to see if any problems were encountered and take appropriate action should that be the case. Next (F) we use YAJL_OBJECT_FIND to locate the Customers object. Note that we supplied a node locator as the first parameter so the API knows where to conduct the search, i.e., the "branch" of the tree in which it should be looking. Needless to say, at the start of the process this is always going to be the root node returned to us by yajl_stmf_load_tree. You might be wondering what would happen if we failed to locate the Customers object. Good question - but we'll defer the answer to later in the discussion when we discuss the handling of optional elements.

G) Demonstrates a useful YAJL function: YAJL_ARRAY_SIZE. This will return the number of elements found in the array identified by the node locator passed to it. In this case we are passing the locator to the Customers array. The code at (H) is included just to demonstrate a way to defend against any problems caused by RPG's fixed array size. In this program we allowed for 99 customers in the array. This code makes sure that we defend against any attempt to process more than that number.

(D)    root
          = yajl_stmf_load_tree ( '/Partner400/Customers.json'
                                : errMsg );

       // If an error was found then report and exit
(E)    if errMsg <> '';
         Dsply 'Ooppppssss - file load problem!';
         // Add appropriate error handling ...
         Return;
       EndIf;

(F)    customersNode = YAJL_OBJECT_FIND( root: 'Customers' );

(G)    elements = YAJL_ARRAY_SIZE( customersNode );

(H)    If elements > %Elem(customer);  // Too many to handle?
          Dsply ('Can only process ' + %Char( %Elem(customer) ) +
                 ' customers - File contains ' + %Char(elements) );
          *InLr = *On;
          Return;
       endif;

Now that we have a locator which points to the Customer array (customersNode) we can use it to process each of the individual customer elements in turn. We do this by using YAJL_ARRAY_LOOP (I) which returns an indicator which will be *On if an element is found, and *Off when there are no more elements to process. That allows us to use a DOW loop to easily iterate through all of the elements in the array. The first parameter (customersNode) is the node we wish to traverse, the second (c) is a counter that identifies the array element number to start from (more on this in a moment) and the third (customerNode) will be used to return the node locator for each array element (i.e., customer).

Two points about the counter (c): The first is that it’s automatically incremented each time the function is called. We can therefore use it as an array index when loading the extracted data into the array DS as you will see in a moment.

The second is that the function uses the counter to determine which element to retrieve. Since we want to start from the first element we had to clear the counter(H) before entering the loop.

Using the retrieved customerNode locator we can now extract the component fields. We begin (J) by using YAJL_OBJECT_FIND to locate the ID field and then extract its value (K) using YAJL_GET_NUMBER. The result is loaded directly into the corresponding element of the customer DS array using the counter as the index. This process is then repeated for each of the customer fields, starting at (L) with the name. Note that for character fields we used YAJL_GET_STRING to perform the corresponding data extraction.

That's all there is to it really.

(H)    c = 0;
      
(I)    Dow YAJL_ARRAY_LOOP( customersNode: c: customerNode );

(J)       idNode = YAJL_OBJECT_FIND( customerNode: 'ID' );
(K)       customer(c).id = YAJL_GET_NUMBER( idNode );

(L)       nameNode = YAJL_OBJECT_FIND( customerNode: 'Name' );
          customer(c).name = YAJL_GET_STRING( nameNode );

          // ... Similar operations performed for all fields ...

       EndDo;

An Alternative Approach

Requesting the value for each field in turn is fine if they are all present. But what if one were missing, either by accident or design (e.g., an optional field)? How could we tell?

Jon Paris is a technical editor with IBM Systems Magazine and co-owner of Partner400.

Susan Gantner is a technical editor with IBM Systems Magazine and co-owner of Partner400.



Like what you just read? To receive technical tips and articles directly in your inbox twice per month, sign up for the EXTRA e-newsletter here.


comments powered by Disqus

Advertisement

Advertisement

2017 Solutions Edition

A Comprehensive Online Buyer's Guide to Solutions, Services and Education.

New and Improved XML-INTO

Namespace support makes the opcode a viable option

Authenticating on the Web

The finer points of OpenRPGUI, Part 1

The Microphone is Open

Add your voice: Should IBM i include open-source RPG tools?

IBM Systems Magazine Subscribe Box Read Now Link Subscribe Now Link iPad App Google Play Store
IBMi News Sign Up Today! Past News Letters