# Example 5 This example program demonstrates the basic structure of an RPG program utilizing RXS to parse JSON data. ### Free Format EX5.rpgle ```rpgle **FREE Ctl-Opt ActGrp(*Caller) BndDir('RXSBND') Option(*NoDebugIO) ExtBinInt(*Yes) DecEdit('0.') Text('Ex. 5 - JSON Parse'); /COPY QRPGLECPY,RXSCB Dcl-S JSON Like(RXS_Var64Kv_t); Dcl-Ds ParseJsonDS LikeDS(RXS_ParseJsonDS_t); JSON = '{ "glossary": { "title": "example glossary", "GlossDiv": { ' + '"title": "S", "GlossList": [ { "ID": "SGML", "SortAs": "SGML", ' + '"GlossTerm": "Standard Generalized Markup Language", "Acronym": ' + '"SGML", "Abbrev": "ISO 8879:1986", "GlossDef": "A meta-markup ' + 'language, used to create markup languages such as DocBook.", ' + '"GlossSeeAlso": ["GML", "XML", "markup", "test"] } ] } } }'; monitor; // Use RXS_ResetDS to ensure that RXS templated data structures are // properly configured before use RXS_ResetDS( ParseJsonDS : RXS_DS_TYPE_PARSEJSON ); // The JSON parsing in RXS functions via an "event-based" method. // Basically, you will create a "handler" subprocedure that will // be called by RXS_ParseJson once for each "event" detected in // the JSON being parsed. An event is one of the following: // - beginning of an JSON Array (RXS_JSON_ARRAY_BEGIN) // - end of an JSON Array (RXS_JSON_ARRAY_END) // - beginning of an JSON Object (RXS_JSON_OBJECT_BEGIN) // - end of an JSON Object (RXS_JSON_OBJECT_END) // - a JSON string value (RXS_JSON_STRING) // - a JSON integer value (RXS_JSON_INTEGER) // - a JSON double (float) value (RXS_JSON_DOUBLE) // - a JSON boolean (indicator) value (RXS_JSON_BOOLEAN) // - a JSON null value (RXS_JSON_NULL) // By default for convenience any numeric, boolean, or null values // will be converted into character strings and passed as RXS_JSON_STRING // events. This can be controlled with a subfield within ParseJsonDS. // Inside the "handler" subprocedure (named JSONHandler here), you // will receive a number of parameters that describe the data // associated with the event detected. JSONHandler() explains this // in more detail ParseJsonDS.Handler = %Paddr( JSONHandler ); RXS_ParseJson( JSON : ParseJsonDS ); on-error; endmon; *INLR = *ON; return; Dcl-Proc JSONHandler; Dcl-Pi *N Ind; pType Int(5) Const; pPath Like(RXS_Var64Kv_t) Const; pIndex Uns(10) Const; pData Pointer Const; pDataLen Uns(10) Const; End-Pi; Dcl-S ParsedData Like(RXS_Var1Kv_t); // JSONHandler must always be specified with the exact same prototype // - the same number of parameters, the same number of field types, in // the same order, etc. The parameters are: // // - pType = the event type, e.g. RXS_JSON_STRING, RXS_JSON_ARRAY_BEGIN, // etc. // - pPath = XPath like syntax that indicates where in the JSON // structure being parsed we are located. You can "drill down" with // slashes (e.g. /object1/field1 corresponds to a 'field1' inside // a parent object named 'object1', and you can indicate when a JSON // JSON Array is present via [*] - further explanation below. // -pIndex = If the JSON object/event we're handling is a child of a // JSON Array, this will indicate the 'index", e.g. the position of // this object within the array, starting from a value of 1. This // parameter is not relevant for objects/events not inside an array // -pData = Pointer to the actual data returned. This will only be set // for RXS_JSON_STRING, RXS_JSON_INTEGER, RXS_JSON_DOUBLE, and // RXS_JSON_BOOLEAN. It is technically also set for RXS_JSON_NULL, // but will be an RPG *Null value. For RXS_JSON_OBJECT, // RXS_JSON_OBJECT_END, RXS_JSON_ARRAY, and RXS_JSON_ARRAY_END, // this will also be *Null as there isn't any data associated with // these events. // -pDataLen = Length of the object. Typically this is used as the // length of pData as a call to RXS_STR as seen below, but pDataLen // is also set to either the total length of a JSON Array or the // number of "first tier" fields in a JSON Object select; // For JSON parsing with RXS, a [*] being part of the path indicates // that an array is involved. If you need to know the specific // position in the array you can look at the pIndex value. Note that // for nested arrays pIndex will show the position of the deepest // JSON Array in the path. when pPath = '/' and pType = RXS_JSON_OBJECT; RXS_JobLog( 'Root object (length %s)' : %Char(pDataLen) ); when pPath = '/glossary' and pType = RXS_JSON_OBJECT; RXS_JobLog( 'glossary object (length %s)' : %Char(pDataLen) ); when pPath = '/glossary/title' and pType = RXS_JSON_STRING; ParsedData = RXS_STR( pData : pDataLen ); RXS_JobLog( 'glossary title: %s' : ParsedData ); when pPath = '/glossary/GlossDiv/title' and pType = RXS_JSON_STRING; ParsedData = RXS_STR( pData : pDataLen ); RXS_JobLog( 'GlossDiv title: %s' : ParsedData ); when pPath = '/glossary/GlossDiv/GlossList[*]' and pType = RXS_JSON_ARRAY; RXS_JobLog( 'Begin GlossList Array (length %s)' : %Char(pDataLen) ); when pPath = '/glossary/GlossDiv/GlossList[*]/ID' and pType = RXS_JSON_STRING; ParsedData = RXS_STR( pData : pDataLen ); RXS_JobLog( 'GlossList Array#%s ID: %s' : %Char(pIndex) : ParsedData ); when pPath = '/glossary/GlossDiv/GlossList[*]/SortAs' and pType = RXS_JSON_STRING; ParsedData = RXS_STR( pData : pDataLen ); RXS_JobLog( 'GlossList Array#%s SortAs: %s' : %Char(pIndex) : ParsedData ); when pPath = '/glossary/GlossDiv/GlossList[*]/GlossTerm' and pType = RXS_JSON_STRING; ParsedData = RXS_STR( pData : pDataLen ); RXS_JobLog( 'GlossList Array#%s GlossTerm: %s' : %Char(pIndex) : ParsedData ); when pPath = '/glossary/GlossDiv/GlossList[*]/Acronym' and pType = RXS_JSON_STRING; ParsedData = RXS_STR( pData : pDataLen ); RXS_JobLog( 'GlossList Array#%s Acronym: %s' : %Char(pIndex) : ParsedData ); when pPath = '/glossary/GlossDiv/GlossList[*]/Abbrev' and pType = RXS_JSON_STRING; ParsedData = RXS_STR( pData : pDataLen ); RXS_JobLog( 'GlossList Array#%s Abbrev: %s' : %Char(pIndex) : ParsedData ); when pPath = '/glossary/GlossDiv/GlossList[*]/GlossDef' and pType = RXS_JSON_STRING; ParsedData = RXS_STR( pData : pDataLen ); RXS_JobLog( 'GlossList Array#%s GlossDef: %s' : %Char(pIndex) : ParsedData ); when pPath = '/glossary/GlossDiv/GlossList[*]/GlossSeeAlso[*]' and pType = RXS_JSON_ARRAY; RXS_JobLog( 'Begin GlossSeeAlso Array (length %s)' : %Char(pDataLen) ); when pPath = '/glossary/GlossDiv/GlossList[*]/GlossSeeAlso[*]' and pType = RXS_JSON_STRING; ParsedData = RXS_STR( pData : pDataLen ); RXS_JobLog( 'GlossSeeAlso Array#%s value: %s' : %Char(pIndex) : ParsedData ); when pPath = '/glossary/GlossDiv/GlossList[*]/GlossSeeAlso[*]' and pType = RXS_JSON_ARRAY_END; RXS_JobLog( 'End GlossSeeAlso Array (length %s)' : %Char(pDataLen) ); when pPath = '/glossary/GlossDiv/GlossList[*]' and pType = RXS_JSON_ARRAY_END; RXS_JobLog( 'End GlossList Array (length %s)' : %Char(pDataLen) ); endsl; // If you want to stop parsing early for whatever reason, return // RXS_JSON_STOP_PARSING return RXS_JSON_CONTINUE_PARSING; End-Proc; ``` ### Fixed Format FX_EX5.rpgle ```rpgle H DFTACTGRP(*NO) ACTGRP(*CALLER) BNDDIR('RXSBND') OPTION(*NODEBUGIO) H EXTBININT(*YES) DECEDIT('0.') H TEXT('Fixed Format Ex. 5 - JSON Parse') /COPY QRPGLECPY,RXSCBaaaq D JSONHandler PR N D pType 5I 0 Const D pPath Const Like(RXS_Var64Kv_t) D pIndex 10U 0 Const D pData * Const D pDataLen 10U 0 Const D JSON S Like(RXS_Var64Kv_t) D ParseJsonDS DS LikeDS(RXS_ParseJsonDS_t) /FREE JSON = '{ "glossary": { "title":' + ' "example glossary", "GlossDiv": { "title": "S", "' + 'GlossList": [ { "ID": "SGML", "SortAs": "SGML", "' + 'GlossTerm": "Standard Generalized Markup Language", "Ac' + 'ronym": "SGML", "Abbrev": "ISO 8879:1986", "GlossDe' + 'f": "A meta-markup language, used to create markup langua' + 'ges such as DocBook.", "GlossSeeAlso": ["GML", "XML"' + ', "markup", "test"] } ] } } }'; monitor; // Use RXS_ResetDS to ensure that RXS templated data structures are // properly configured before use RXS_ResetDS( ParseJsonDS : RXS_DS_TYPE_PARSEJSON ); // The JSON parsing in RXS functions via an "event-based" method. // Basically, you will create a "handler" subprocedure that will // be called by RXS_ParseJson once for each "event" detected in // the JSON being parsed. An event is one of the following: // - beginning of an JSON Array (RXS_JSON_ARRAY_BEGIN) // - end of an JSON Array (RXS_JSON_ARRAY_END) // - beginning of an JSON Object (RXS_JSON_OBJECT_BEGIN) // - end of an JSON Object (RXS_JSON_OBJECT_END) // - a JSON string value (RXS_JSON_STRING) // - a JSON integer value (RXS_JSON_INTEGER) // - a JSON double (float) value (RXS_JSON_DOUBLE) // - a JSON boolean (indicator) value (RXS_JSON_BOOLEAN) // - a JSON null value (RXS_JSON_NULL) // By default for convenience any numeric, boolean, or null values // will be converted into character strings and passed as // RXS_JSON_STRING events. This can be controlled with a subfield // within ParseJsonDS. // Inside the "handler" subprocedure (named JSONHandler here), you // will receive a number of parameters that describe the data // associated with the event detected. JSONHandler() explains this // in more detail ParseJsonDS.Handler = %Paddr( JSONHandler ); RXS_ParseJson( JSON : ParseJsonDS ); on-error; endmon; *INLR = *ON; return; /END-FREE P JSONHandler B Export D PI N D pType 5I 0 Const D pPath Const Like(RXS_Var64Kv_t) D pIndex 10U 0 Const D pData * Const D pDataLen 10U 0 Const * D ParsedData S Like(RXS_Var1Kv_t) /FREE // JSONHandler must always be specified with the exact same prototype // - the same number of parameters, the same number of field types, in // the same order, etc. The parameters are: // // - pType = the event type, e.g. RXS_JSON_STRING, RXS_JSON_ARRAY_BEGIN, // etc. // - pPath = XPath like syntax that indicates where in the JSON // structure being parsed we are located. You can "drill down" with // slashes (e.g. /object1/field1 corresponds to a 'field1' inside // a parent object named 'object1', and you can indicate when a JSON // JSON Array is present via [*] - further explanation below. // -pIndex = If the JSON object/event we're handling is a child of a // JSON Array, this will indicate the 'index", e.g. the position of // this object within the array, starting from a value of 1. This // parameter is not relevant for objects/events not inside an array // -pData = Pointer to the actual data returned. This will only be set // for RXS_JSON_STRING, RXS_JSON_INTEGER, RXS_JSON_DOUBLE, and // RXS_JSON_BOOLEAN. It is technically also set for RXS_JSON_NULL, // but will be an RPG *Null value. For RXS_JSON_OBJECT, // RXS_JSON_OBJECT_END, RXS_JSON_ARRAY, and RXS_JSON_ARRAY_END, // this will also be *Null as there isn't any data associated with // these events. // -pDataLen = Length of the object. Typically this is used as the // length of pData as a call to RXS_STR as seen below, but pDataLen // is also set to either the total length of a JSON Array or the // number of "first tier" fields in a JSON Object select; // For JSON parsing with RXS, a [*] being part of the path indicates // that an array is involved. If you need to know the specific // position in the array you can look at the pIndex value. Note that // for nested arrays pIndex will show the position of the deepest // JSON Array in the path. when pPath = '/' and pType = RXS_JSON_OBJECT; RXS_JobLog( 'Root object (length %s)' : %Char(pDataLen) ); when pPath = '/glossary' and pType = RXS_JSON_OBJECT; RXS_JobLog( 'glossary object (length %s)' : %Char(pDataLen) ); when pPath = '/glossary/title' and pType = RXS_JSON_STRING; ParsedData = RXS_STR( pData : pDataLen ); RXS_JobLog( 'glossary title: %s' : ParsedData ); when pPath = '/glossary/GlossDiv/title' and pType = RXS_JSON_STRING; ParsedData = RXS_STR( pData : pDataLen ); RXS_JobLog( 'GlossDiv title: %s' : ParsedData ); when pPath = '/glossary/GlossDiv/GlossList[*]' and pType = RXS_JSON_ARRAY; RXS_JobLog( 'Begin GlossList Array (length %s)' : %Char(pDataLen) ); when pPath = '/glossary/GlossDiv/GlossList[*]/ID' and pType = RXS_JSON_STRING; ParsedData = RXS_STR( pData : pDataLen ); RXS_JobLog( 'GlossList Array#%s ID: %s' : %Char(pIndex) : ParsedData ); when pPath = '/glossary/GlossDiv/GlossList[*]/SortAs' and pType = RXS_JSON_STRING; ParsedData = RXS_STR( pData : pDataLen ); RXS_JobLog( 'GlossList Array#%s SortAs: %s' : %Char(pIndex) : ParsedData ); when pPath = '/glossary/GlossDiv/GlossList[*]/GlossTerm' and pType = RXS_JSON_STRING; ParsedData = RXS_STR( pData : pDataLen ); RXS_JobLog( 'GlossList Array#%s GlossTerm: %s' : %Char(pIndex) : ParsedData ); when pPath = '/glossary/GlossDiv/GlossList[*]/Acronym' and pType = RXS_JSON_STRING; ParsedData = RXS_STR( pData : pDataLen ); RXS_JobLog( 'GlossList Array#%s Acronym: %s' : %Char(pIndex) : ParsedData ); when pPath = '/glossary/GlossDiv/GlossList[*]/Abbrev' and pType = RXS_JSON_STRING; ParsedData = RXS_STR( pData : pDataLen ); RXS_JobLog( 'GlossList Array#%s Abbrev: %s' : %Char(pIndex) : ParsedData ); when pPath = '/glossary/GlossDiv/GlossList[*]/GlossDef' and pType = RXS_JSON_STRING; ParsedData = RXS_STR( pData : pDataLen ); RXS_JobLog( 'GlossList Array#%s GlossDef: %s' : %Char(pIndex) : ParsedData ); when pPath = '/glossary/GlossDiv/GlossList[*]/GlossSeeAlso[*]' and pType = RXS_JSON_ARRAY; RXS_JobLog( 'Begin GlossSeeAlso Array (length %s)' : %Char(pDataLen) ); when pPath = '/glossary/GlossDiv/GlossList[*]/GlossSeeAlso[*]' and pType = RXS_JSON_STRING; ParsedData = RXS_STR( pData : pDataLen ); RXS_JobLog( 'GlossSeeAlso Array#%s value: %s' : %Char(pIndex) : ParsedData ); when pPath = '/glossary/GlossDiv/GlossList[*]/GlossSeeAlso[*]' and pType = RXS_JSON_ARRAY_END; RXS_JobLog( 'End GlossSeeAlso Array (length %s)' : %Char(pDataLen) ); when pPath = '/glossary/GlossDiv/GlossList[*]' and pType = RXS_JSON_ARRAY_END; RXS_JobLog( 'End GlossList Array (length %s)' : %Char(pDataLen) ); endsl; // If you want to stop parsing early for whatever reason, return // RXS_JSON_STOP_PARSING return RXS_JSON_CONTINUE_PARSING; /END-FREE P E ```