RXS_ParseJson()
This subprocedure provides event-based parsing for JSON documents. Using this subprocedure requires a handler subprocedure.
All JSON parsing subprocedures must have the following prototype:
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
The JSON parser recognizes the following element events:
Event | pType Constant | pPath Format | Example | |||
---|---|---|---|---|---|---|
Array Start | RXS_JSON_ARRAY |
[*] |
/phone[*] |
|||
Array End | RXS_JSON_ARRAY_END |
[*] |
/phone[*] |
|||
Object Start | RXS_JSON_OBJECT |
/ |
/phone |
|||
Object End | RXS_JSON_OBJECT_END |
/ |
/phone |
Because the start and end events share the same path structure, you will also need to check the value of the pType parameter.
By default, the JSON parser returns all values as character data. In order to retrieve values in their respective RPG data types, you must set the value of ConvertDataToString to RXS_NO in the RXS_ParseJsonDS_t data structure. The JSON parser recognizes the following content types:
JSON Data Type | pType Constant | RPG Data Type | ||
---|---|---|---|---|
String | RXS_JSON_STRING |
A |
||
Boolean | RXS_JSON_BOOLEAN |
N |
||
Integer | RXS_JSON_INTEGER |
20I 0 |
||
Double | RXS_JSON_DOUBLE |
8F |
||
Null | RXS_JSON_NULL |
n/a |
For a detailed example of JSON parsing, please see this blog post: Parsing JSON with RPG-XML Suite 3.3.
This subprocedure can optionally return a RXS_JsonStructureDS_t data structure which can be used with the RXS JSON composition subprocedures.
Subprocedure Prototype
|
Returns an RXS_JsonStructureDS_t which can be used by the RXS JSON composition subprocedures. |
|
Holds the JSON data to be passed to the parsing subprocedure. Will be ignored if the Stmf subfield of the pParseJsonDS parameter is set. |
|
RXS_ParseJsonDS_t data structure which controls how RXS_ParseJson() functions. |
Example Code
*--------------------------------------------------------------
* This example parses a simple JSON structure stored in the
* field 'JSON' and stores the data contained in fields 'id',
* 'name', and 'price' in the corresponding global fields.
*
* At a high level, the JSON is parsed into the JsonHandler()
* in small chunks. Then, a SELECT block is used to detect whether
* or not the current JSON element matches one you'd like to
* handle. If it does, you can extract the data using RXS_STR().
*
* Once the JSON has been entirely passed through JsonHandler(),
* control returns to the main portion of the program.
*--------------------------------------------------------------
H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER)
/copy QRPGLECPY,RXSCB
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 ParseJsonDS DS LikeDS(RXS_ParseJsonDS_t)
D JSON S Like(RXS_Var64Kv_t)
D id S Like(RXS_Var1Kv_t)
D name S Like(RXS_Var1Kv_t)
D price S 6P 2
/free
// JSON structure looks like this:
// {
// "item": {
// "id": 7,
// "name": "headlight fluid",
// "price": 12.50
// }
// }
JSON = '{ "item": { "id": 7, "name": "headlight fluid",' +
'"price": 12.50 } }';
RXS_ResetDS( ParseJsonDS : RXS_DS_TYPE_PARSEJSON );
ParseJsonDS.Handler = %Paddr( JsonHandler );
RXS_ParseJson( JSON : ParseJsonDS );
RXS_JobLog( 'id: %s' : id );
RXS_JobLog( 'name: %s' : name );
RXS_JobLog( 'price: %s' : %Char(price) );
*INLR = *ON;
/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
/free
select;
when pPath = '/item/id';
// All data in the JSON being parsed is returned
// as a character data field. If you need the data
// to be in a different data type, you can use %Int()
// or %Dec() to further convert it as shown further
// below.
id = RXS_STR( pData : pDataLen );
when pPath = '/item/name';
name = RXS_STR( pData : pDataLen );
when pPath = '/item/price';
monitor;
price = %Dec( RXS_STR( pData : pDataLen ) : 6 : 2 );
on-error 105;
RXS_JobLog( 'Error converting price!' );
return *Off;
endmon;
endsl;
return *On;
/end-free
P E
*--------------------------------------------------------------
* This example parses a simple JSON structure stored in the
* field 'JSON' and stores the data contained in fields 'id',
* 'name', and 'price' in the corresponding global fields.
*
* This example differs from Example 1 in that instead of
* returning all values as character data, values will be
* returned using the RPG equivalents of the JSON data types.
*
* Doing this is somewhat more complicated, and may not be useful
* in many JSON parsing situations, so this is not the default
* behavior of RXS_ParseJson().
*--------------------------------------------------------------
H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER)
/copy QRPGLECPY,RXSCB
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 ParseJsonDS DS LikeDS(RXS_ParseJsonDS_t)
D JSON S Like(RXS_Var64Kv_t)
D id S 20I 0
D name S Like(RXS_Var1Kv_t)
D price S 6P 2
D sale S N
/free
// JSON structure looks like this:
// {
// "item": {
// "id": 7,
// "name": "headlight fluid",
// "price": 12.50,
// "sale": true
// }
// }
JSON = '{ "item": { "id": 7, "name": "headlight fluid",' +
'"price": 12.50, "sale": true } }';
RXS_ResetDS( ParseJsonDS : RXS_DS_TYPE_PARSEJSON );
ParseJsonDS.Handler = %Paddr( JsonHandler );
// By default this value is RXS_YES, meaning that all data
// returned will be converted into character data before
// it is available inside JsonHandler. Setting this to RXS_NO
// means that JsonHandler will instead be receiving RPG data
// types beyond character fields, such as integers, indicators,
// and floating point numbers.
ParseJsonDS.ConvertDataToString = RXS_NO;
RXS_ParseJson( JSON : ParseJsonDS );
RXS_JobLog( 'id: %s' : %Char(id) );
RXS_JobLog( 'name: %s' : name );
RXS_JobLog( 'price: %s' : %Char(price) );
if sale;
RXS_JobLog( 'sale: %s' : 'true' );
else;
RXS_JobLog( 'sale: %s' : 'false' );
endif;
*INLR = *ON;
/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
* To return native JSON types, we have to make use of Basing pointers
* and pay careful attention to the pType parameter. Please note that
* JSON has two types of numbers - integer and float. Floating point
* numbers are not precise, and values returned by RXS_ParseJson
* for floating-point numbers may differ slighltly from how they
* appear in the JSON. If your JSON data is going to contain
* decimal values it is advised to parse JSON using the default
* behavior where all parsed data is converted to character data
* before being returned to avoid a loss of precision.
D BoolVal S N Based(pData)
D IntVal S 20I 0 Based(pData)
D FloatVal S 8F Based(pData)
/free
select;
when pPath = '/item/id';
// We know that the 'id' field is an integer, so we can simply
// do the following:
id = IntVal;
// Note that integers are always going to be returned as 8 byte
// integers, e.g. 20I 0. Using 3I 0, 5I 0, or 10I 0 will not work.
when pPath = '/item/name';
// 'name' is character data, and should be handled the same way
name = RXS_STR( pData : pDataLen );
when pPath = '/item/price';
// 'price' is stored in the JSON as a decimal. We know from context
// that price is denoting a monetary value, which is a situation
// where the loss of precision using a floating point number brings
// is completely unacceptable. For example, instead of returning
// 12.50 as we would expect, we might get 12.501 or 12.499. This
// would make a large difference to a business! However, as this
// is example code, below demonstrates returning floating point
// numbers:
price = FloatVal;
when pPath = '/item/sale';
// We know that the 'id' field is a boolean value. It's important to
// know that a JSON character data value of 'true' is different from
// the JSON boolean data value of true. The two items below are not
// equivalent:
//
// {
// "item1": 'true',
// "item2" : true
// }
// The RPG equivalent of a boolean data type is an indicator field.
sale = BoolVal;
endsl;
return *On;
/end-free
P E
*--------------------------------------------------------------
* This example parses a simple JSON structure stored in the
* field 'JSON' and stores the data contained in fields 'id',
* 'name', and 'price' in the corresponding global fields.
*
* At a high level, the JSON is parsed into the JsonHandler()
* in small chunks. Then, a SELECT block is used to detect whether
* or not the current JSON element matches one you'd like to
* handle. If it does, you can extract the data using RXS_STR().
*
* Once the JSON has been entirely passed through JsonHandler(),
* control returns to the main portion of the program.
*--------------------------------------------------------------
H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER)
/define RXSV6R1
/copy QRPGLECPY,RXSCB
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 ParseJsonDS DS LikeDS(RXS_ParseJsonDS_t)
D JSON S Like(RXS_Var64Kv_t)
D id S Like(RXS_Var1Kv_t)
D name S Like(RXS_Var1Kv_t)
D price S 6P 2
/free
// JSON structure looks like this:
// {
// "item": {
// "id": 7,
// "name": "headlight fluid",
// "price": 12.50
// }
// }
JSON = '{ "item": { "id": 7, "name": "headlight fluid",' +
'"price": 12.50 } }';
RXS_ResetDS( ParseJsonDS : RXS_DS_TYPE_PARSEJSON );
ParseJsonDS.Handler = %Paddr( JsonHandler );
RXS_ParseJson( JSON : ParseJsonDS );
RXS_JobLog( 'id: %s' : id );
RXS_JobLog( 'name: %s' : name );
RXS_JobLog( 'price: %s' : %Char(price) );
*INLR = *ON;
/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
select;
when pPath = '/item/id';
// All data in the JSON being parsed is returned
// as a character data field. If you need the data
// to be in a different data type, you can use %Int()
// or %Dec() to further convert it as shown further
// below.
RXS_STR( ParsedData : pData : pDataLen );
id = ParsedData;
when pPath = '/item/name';
RXS_STR( id : pData : pDataLen );
name = ParsedData;
when pPath = '/item/price';
ParsedData = RXS_STR( pData : pDataLen );
monitor;
price = %Dec( ParsedData : 6 : 2 );
on-error 105;
price = 0;
RXS_JobLog( 'Error converting price!' );
return *Off;
endmon;
endsl;
return *On;
/end-free
P E
*--------------------------------------------------------------
* This example parses a simple JSON structure stored in the
* field 'JSON' and stores the data contained in fields 'id',
* 'name', and 'price' in the corresponding global fields.
*
* This example differs from Example 1 in that instead of
* returning all values as character data, values will be
* returned using the RPG equivalents of the JSON data types.
*
* Doing this is somewhat more complicated, and may not be useful
* in many JSON parsing situations, so this is not the default
* behavior of RXS_ParseJson().
*--------------------------------------------------------------
H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER)
/copy QRPGLECPY,RXSCB
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 ParseJsonDS DS LikeDS(RXS_ParseJsonDS_t)
D JSON S Like(RXS_Var64Kv_t)
D id S 20I 0
D name S Like(RXS_Var1Kv_t)
D price S 6P 2
D sale S N
/free
// JSON structure looks like this:
// {
// "item": {
// "id": 7,
// "name": "headlight fluid",
// "price": 12.50,
// "sale": true
// }
// }
JSON = '{ "item": { "id": 7, "name": "headlight fluid",' +
'"price": 12.50, "sale": true } }';
RXS_ResetDS( ParseJsonDS : RXS_DS_TYPE_PARSEJSON );
ParseJsonDS.Handler = %Paddr( JsonHandler );
// By default this value is RXS_YES, meaning that all data
// returned will be converted into character data before
// it is available inside JsonHandler. Setting this to RXS_NO
// means that JsonHandler will instead be receiving RPG data
// types beyond character fields, such as integers, indicators,
// and floating point numbers.
ParseJsonDS.ConvertDataToString = RXS_NO;
RXS_ParseJson( JSON : ParseJsonDS );
RXS_JobLog( 'id: %s' : %Char(id) );
RXS_JobLog( 'name: %s' : name );
RXS_JobLog( 'price: %s' : %Char(price) );
if sale;
RXS_JobLog( 'sale: %s' : 'true' );
else;
RXS_JobLog( 'sale: %s' : 'false' );
endif;
*INLR = *ON;
/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
* To return native JSON types, we have to make use of Basing pointers
* and pay careful attention to the pType parameter. Please note that
* JSON has two types of numbers - integer and float. Floating point
* numbers are not precise, and values returned by RXS_ParseJson
* for floating-point numbers may differ slighltly from how they
* appear in the JSON. If your JSON data is going to contain
* decimal values it is advised to parse JSON using the default
* behavior where all parsed data is converted to character data
* before being returned to avoid a loss of precision.
D BoolVal S N Based(pData)
D IntVal S 20I 0 Based(pData)
D FloatVal S 8F Based(pData)
/free
select;
when pPath = '/item/id';
// We know that the 'id' field is an integer, so we can simply
// do the following:
id = IntVal;
// Note that integers are always going to be returned as 8 byte
// integers, e.g. 20I 0. Using 3I 0, 5I 0, or 10I 0 will not work.
when pPath = '/item/name';
// 'name' is character data, and should be handled the same way
name = RXS_STR( pData : pDataLen );
when pPath = '/item/price';
// 'price' is stored in the JSON as a decimal. We know from context
// that price is denoting a monetary value, which is a situation
// where the loss of precision using a floating point number brings
// is completely unacceptable. For example, instead of returning
// 12.50 as we would expect, we might get 12.501 or 12.499. This
// would make a large difference to a business! However, as this
// is example code, below demonstrates returning floating point
// numbers:
price = FloatVal;
when pPath = '/item/sale';
// We know that the 'id' field is a boolean value. It's important to
// know that a JSON character data value of 'true' is different from
// the JSON boolean data value of true. The two items below are not
// equivalent:
//
// {
// "item1": 'true',
// "item2" : true
// }
// The RPG equivalent of a boolean data type is an indicator field.
sale = BoolVal;
endsl;
return *On;
/end-free
P E
Data Structures
|
|
|
|
|
Internal use only |
|
|
|
Holds a PROCPTR to a JsonHandler subprocedure to handle all possible parsed JSON events. |
|
Internal use only |
|
Internal use only |
|
Specifies the CCSID of the JSON being parsed. Default Value: |
|
Specifies the CCSID the parsed data will be converted to. Default Value: |
|
Specifies an IFS path to a JSON file to parse instead of the pInput parm. |
|
Internal use only |