# RPG API Express 3.2 Documentation --- # RPG-XML Suite 3.2x System Requirements > Lists supported IBM i OS versions (7.3-7.6), required features (Apache, QShell), and installation prerequisites for RPG API Express 3.2.x. ## Installed Feature Requirements - RPG API Express requires Apache which is installed on 99% of all machines we come in contact with. Note that Apache only needs to be started if you are offering web services from your IBM i. If you are only acting as the client role and making a request to another server *from* the IBM i, then you don't need to start the Apache server. - We use QShell during the install so that is also required and is already installed on most machines. It is **5722SS1 opt 30**. ## Operating System Level Support RPG API Express 3.2x can be used on the following operating system versions: - IBM i OS 7.6 - IBM i OS 7.5 - IBM i OS 7.4 - IBM i OS 7.3 - IBM i OS 7.2 - IBM i OS 7.1 - IBM i OS 6.1 --- # Installing RPG-XML Suite 3.2x > Step-by-step installation guide covering file transfer, library restoration, HTTP server creation, license activation, and verification. RPG-XML Suite is available as a fully-featured 30 day free trial. To request a trial and a free customized proof of concept program, please [contact us](https://www.rpg-xml.com/contact-us/). 1. Unzip the downloaded file to `C:\temp` (or the directory of your choice). 2. Create the \*SAVF to upload to on your IBM i: `CRTSAVF FILE(QGPL/RXS) AUT(*ALL)` 3. FTP the file RXS.SAVF from your PC to the IBM i. Open a DOS prompt (Start -> Run -> enter 'cmd' and hit enter). Type the following into the DOS prompt, replacing the IP address with that of your IBM i. When prompted, enter your IBM i username and password. 1. `ftp 123.456.789.123` 2. `binary` 3. `lcd c:\temp` 4. `quote site namefmt 0` 5. `cd QGPL` 6. `put rxs.savf rxs.savf` 7. `quit` 4. Issue the following IBM i commands. The value 'RXS' is used to denote where the base install of RPG-XML Suite should reside. Note that 8181 is the default port your RXS runs under in Apache. Change it to meet your needs. The default of 8181 should be fine 99% of the time. 1. `RSTLIB SAVLIB(RXS) DEV(*SAVF) SAVF(QGPL/RXS) RSTLIB(RXS)` 2. `ADDLIBLE RXS` 3. `CRTRXSSVR HTTPSVR(*RXSLIB) RXSLIB(RXS) PORT(8181)` 5. Registration - When you downloaded RXS, you should have been prompted to enter in a valid email address. An email should have been sent to that address specifying an APYLIC command similar to the one below. Issue the emailed command using copy-and-paste to avoid input errors. `APYLIC LICKEY(<>) PRODUCT(RXS)` 6. Start the HTTP server using the below command: `HTTP HTTPSVR(RXS) OPTION(*START)` 7. Open your internet browser and enter the following while substituting your IBMi IP address: `http://yourIBMiIP:8181/debug` You should see a page used for general debugging of the RPG-XML Suite Router. If you see this page, then the RXS Router is installed properly. 8. Open your internet browser and enter the following while substituting your IBMi IP address: `http://yourIBMiIP:8181/MYRXS/rxs1` You should get the following result: `I love home improvement plumbing. Especially when it leaks after you turn on the water!` --- # Upgrading RPG-XML Suite 3.2x > Upgrade procedures for single and multiple library installations, including RSTOBJ commands, library list management, and Apache instance handling. The upgrade process for RPG-XML Suite is dependent on how many libraries contain RPG-XML Suite objects. You can determine if RPG-XML Suite is installed in multiple libraries with this command: `WRKOBJ OBJ(*ALL/RXS*) OBJTYPE(*SRVPGM)` If the WRKOBJ command lists only library RXS, you should use the upgrade instructions for **Single Library Installation** below. If the WRKOBJ command lists libraries other than RXS, please use the upgrade instructions for **Multiple Library Installation** below. ### Single Library Installation **Note:** - `@@` is the version number of the source/current version level (example: 22) - `###` is the version number of the target/new version level (example: 310) For clarity, you may wish to copy these instructions to a text editor and then perform a scan and replace for the above values before beginning the upgrade. 1. Unzip the downloaded upgrade file to `C:\temp` (or the directory of your choice). 2. Issue the IBM i command: `CRTSAVF FILE(QGPL/RXS###) AUT(*ALL)` 3. FTP the file rxs.savf from your PC to the IBM i in BINARY mode into the save file just created. 1. Open a DOS prompt (Start -> Run -> enter 'cmd' and hit enter) 2. Type the following into the DOS prompt, replacing the IP address with that of your iSeries: `ftp 172.29.134.41` 3. When prompted enter user profile and password 1. `binary` 2. `lcd c:\temp (where c:\temp is the location of the rxs.savf on your local computer)` 3. `quote site namefmt 0` 4. `cd QGPL` 5. `put rxs.savf rxs###.savf` 6. `quit` 4. End all RPG-XML Suite Apache instances. Note that this will mean your web services are **NOT** accessible! Execute the following IBM i command: `ENDTCPSVR SERVER(*HTTP) HTTPSVR(RXS)` **Note:** Be sure to execute this command for any custom instances that also use RPG-XML Suite. 5. Perform a full backup of library RXS. 6. Execute the following IBM i command to upgrade the library RXS (this is all one command): `RSTOBJ OBJ(*ALL) SAVLIB(RXS) MBROPT(*ALL) ALWOBJDIF(*FILELVL *OWNER) OMITOBJ((RXSUNQ) (RXSCFG) (LICP) (RXSRTRCTL) (RXSRTRLOG)) RSTLIB(RXS) DEV(*SAVF) SAVF(QGPL/RXS###)` **Note:** If any of the objects listed in OMITOBJ **do NOT** already exist in library RXS, then remove them from the OMITOBJ parameter. This is most common if your pre-upgrade version is previous to 2.80. 7. Execute the following IBM i commands when files RXS/RXSRTRCTL and RXS/RXSRTRLOG do **NOT** already have a RXSRTR member: 1. `RNMM FILE(RXS/RXSRTRCTL) MBR(RXSRTRCTL) NEWMBR(RXSRTR)` 2. `RNMM FILE(RXS/RXSRTRLOG) MBR(RXSRTRLOG) NEWMBR(RXSRTR)` 3. `CHGPF FILE(RXS/RXSRTRCTL) MAXMBRS(32)` 4. `CHGPF FILE(RXS/RXSRTRLOG) MAXMBRS(32)` 8. Execute the following IBM i commands when your pre-upgrade version was previous to version 2.80 and if you **do not** have a library named KTLIC on your IBM i: 1. `RMVLIBLE LIB(RXS)` 2. `ADDLIBLE LIB(RXS) POSITION(*FIRST)` 3. `APYLIC LICKEY(<>) PRODUCT(RXS)` If you have a library named KTLIC on your IBM i, the commands above do not apply. Please contact support for further instructions. 9. Restart all RPG-XML Suite Apache instances: `STRTCPSVR SERVER(*HTTP) HTTPSVR(RXS)` **Note:** Be sure to execute this command for any custom instances that also use RPG-XML Suite. ### Multiple Library Installation If you haven't yet, run the following command: `WRKOBJ OBJ(*ALL/RXS*) OBJTYPE(*SRVPGM)` Using the libraries output by the WRKOBJ command, please make a list of the libraries which need to be upgraded, but do not include RXS library on the list. There should be an Apache instance for each library and the instance name should be the same as the library. As you continue with these instructions, this list will be referred to as the "Upgrade List". The library and Apache instance named MYRXS will be referenced in the instructions as you continue, but MYRXS may, or may not, be on your Upgrade List. If MYRXS is not on the Upgrade List, please substitute all libraries which do appear on the list in place of references to MYRXS. If MYRXS is on the Upgrade List, please follow the instructions that reference MYRXS and then also duplicate those instructions for any other libraries/instances on the list in addition to MYRXS. **Note:** - `@@` is the version number of the source/current version level (example: 22) - `###` is the version number of the target/new version level (example: 310) For clarity, you may wish to copy these instructions to a text editor and then perform a scan and replace for the above values before beginning the upgrade. 1. Unzip the downloaded upgrade file to `C:\temp` (or the directory of your choice). 2. Issue the IBM i command: `CRTSAVF FILE(QGPL/RXS###) AUT(*ALL)` 3. FTP the file rxs.savf from your PC to the IBM i in BINARY mode into the save file just created. 1. Open a DOS prompt (Start -> Run -> enter 'cmd' and hit enter) 2. Type the following into the DOS prompt, replacing the IP address with that of your iSeries: `ftp 172.29.134.41` 3. When prompted enter user profile and password 1. `binary` 2. `lcd c:\temp (where c:\temp is the location of the rxs.savf on your local computer)` 3. `quote site namefmt 0` 4. `cd QGPL` 5. `put rxs.savf rxs###.savf` 6. `quit` 4. End all RPG-XML Suite Apache instances. Note that this will mean your web services are **NOT** accessible! Execute the following IBM i command to end the Apache instances, while substituting the instance names from the Upgrade List for MYRXS: `ENDTCPSVR SERVER(*HTTP) HTTPSVR(MYRXS)` **Note:** Be sure to execute this command for any custom instances that also use RPG-XML Suite. 5. Perform full backups of library RXS and all libraries on the Upgrade List. 6. Execute the following IBM i command to upgrade the library RXS (this is all one command): `RSTOBJ OBJ(*ALL) SAVLIB(RXS) DEV(*SAVF) SAVF(QGPL/RXS###) MBROPT(*ALL) ALWOBJDIF(*FILELVL *OWNER) RSTLIB(RXS) OMITOBJ((RXSUNQ) (RXSCFG) (LICP)(RXSRTRCTL)(RXSRTRLOG))` **Note:** If any of the objects listed in OMITOBJ **do NOT** already exist in library RXS, then remove them from the OMITOBJ parameter. This is most common if your pre-upgrade version is previous to 2.80. 7. Execute the following IBM i commands when file RXS/RXSRTRCTL **does NOT** already exist: `RSTOBJ OBJ(RXSRTRCTL RXSRTRLOG) SAVLIB(RXS) DEV(*SAVF) SAVF(QGPL/RXS###) RSTLIB(RXS)` 8. Execute the following IBM i commands when files RXS/RXSRTRCTL and RXS/RXSRTRLOG **do NOT** already have a RXSRTR member: 1. `RNMM FILE(RXS/RXSRTRCTL) MBR(RXSRTRCTL) NEWMBR(RXSRTR)` 2. `RNMM FILE(RXS/RXSRTRLOG) MBR(RXSRTRLOG) NEWMBR(RXSRTR)` 3. `CHGPF FILE(RXS/RXSRTRCTL) MAXMBRS(32)` 4. `CHGPF FILE(RXS/RXSRTRLOG) MAXMBRS(32)` 9. Execute the following IBM i commands when your pre-upgrade version was previous to version 2.80 and if you **do not** have a library named KTLIC on your IBM i: 1. `RMVLIBLE LIB(RXS)` 2. `ADDLIBLE LIB(RXS) POSITION(*FIRST)` 3. `APYLIC LICKEY(<>) PRODUCT(RXS)` If you have a library named KTLIC on your IBM i, the commands above do not apply. Please contact support for further instructions. 10. Execute the following IBM i commands to upgrade all the libraries on the Upgrade List, while substituting the names from the Upgrade List for MYRXS: 1. `RSTOBJ OBJ(*ALL) SAVLIB(RXS) DEV(*SAVF) SAVF(QGPL/RXS###) MBROPT(*ALL) ALWOBJDIF(*FILELVL *OWNER) RSTLIB(MYRXS) OMITOBJ((RXSUNQ) (RXSCFG) (LICP) (INSTALL) (NEWENV) (HTTP*) (DSPMCH*) (CRTRXS*) (QTXT) (REGRXSBASE) (VER*) (RXSRTR* *FILE) (*ALL *PNLGRP) (RXSURI*) (DSPVER) (RXSMENU*) (INZ*) (WRK*) (CRT*))` 2. `CPYF FROMFILE(RXS/LICP) TOFILE(MYRXS/LICP) MBROPT(*REPLACE) CRTFILE(*YES)` 11. Restart all RPG-XML Suite Apache server instances by executing the following command, while substituting the names from the Upgrade List for MYRXS: `STRTCPSVR SERVER(*HTTP) HTTPSVR(MYRXS)` **Note:** Be sure to execute this command for each instance name on the Upgrade List. --- # Uninstalling RPG-XML Suite > Covers removing RPG API Express by terminating Apache instances, deleting the library, and removing IFS directories. RPG-XML Suite licenses may be transferred to a different IBM i, or a different partition. Part of this process will involve uninstalling the product from the original machine/partition. 1. End the Apache server instance: `ENDTCPSVR SERVER(*HTTP) HTTPSVR(RXS)` 2. Delete the RPG-XML Suite install library: `DLTLIB RXS` 3. Run QShell command to recursively remove the RXS directory and everything in it: `QSH CMD('rm -Rf /www/RXS')` 4. Run QShell command to recursively remove the /krengeltech directory and everything in it: `QSH CMD('rm -Rf /krengeltech')` 5. Remove the Apache server instance from OS/400: `RMVM FILE(QUSRSYS/QATMHINSTC) MBR(RXS)` 6. If the below command does not return "Data area RXSBASE in QGPL not found.": `DSPDTAARA DTAARA(QGPL/RXSBASE)` Call this command to delete the RXS license object: `DLTOBJ OBJ(QGPL/RXSBASE) OBJTYPE(*DTAARA)` --- # Replication Instructions > Specifies objects to exclude from replication (QGPL/RXSBASE, LICP files) to prevent licensing errors on replicated systems. If the following objects exist in your RPG-XML Suite installation, they should be excluded from replication. Failure to do this will cause licensing errors. - QGPL/RXSBASE *DTAARA - RXS/LICP *FILE - Any other LICP *FILE objects present in RXS instance libraries (ex. MYRXS) --- # License Transfer > Explains how to transfer an RPG API Express license from one IBM i system or partition to another. RPG-XML Suite licenses may be transferred to a different IBM i, or a different partition. To do this, you will need to provide us with screenshots of the following information with the RXS library in your library list: - The currently installed version of RPG-XML Suite: `CALL RXS/VERRXSBASE` - Machine info for each LPAR a license is being moved from: `DSPMCHINF` - Machine info for each LPAR a license is being moved to: `DSPMCHINF` If you don't currently have access to the system you're migrating to, please let us know and we can provide a temporary license until you can provide information for us to generate a permanent license key. Please email this information to isupport@katointegrations.com. --- # RXS Changelog > Version history for RPG API Express, detailing changes per release. ## 3.5.3 - [New] **New feature:** Added new parameter AUTOSTART to CRTRXSSVR command to allow configuring the HTTP server's autostart property at creation time - [New] **New feature:** Added new value *CFGAUTO for HTTP command parameter OPTION to enable new parameter AUTOSTART which allows modifying the HTTP server's autostart property after creation - [New] **New feature:** Added new parameter STMFCCSID to RXSURI command to allow configuring the CCSID used to create response IFS stream files - Enhanced subprocedures with more aggressive checking of input parameter data structure types to avoid unintended behavior. **If an existing program is incorrectly relying on using the wrong data structure for an RXS subprocedure, you may experience new runtime errors after upgrading.** - Enhanced RXS_HMACDS_t with new subfield ReturnMode which accepts the constants RXS_RETURN_MODE_BYTES, RXS_RETURN_MODE_CHAR_UPPER, and RXS_RETURN_MODE_CHAR_LOWER to allow the value returned from RXS_HMAC to be returned as raw bytes, uppercase characters, or lowercase characters. ReturnMode replaces/overlays the existing subfield ReturnAsChar which only allowed raw bytes or uppercase characters to be returned by RXS_HMAC - Enhanced RXS_ParseJsonDS_t with new subfield ParseMode which accepts the constants RXS_JSON_PARSE_DEFAULT, RXS_JSON_PARSE_NATIVE, and RXS_JSON_PARSE_NULL_EMPTY to allow the parsed values made available in a parsing handler subprocedure to be returned as either converted to character data, provided as native RPG data types, or converted to character data but with null values converted to an empty string. ParseMode replaces/overlays the existing subfield ConvertDataToString which only allowed values to be converted to character data or native RPG data types - Enhanced RXS Router to pull Initial ASP group from a *JOBD specified for -liblst or -dftliblst to provide further compatibility with iASPs - Enhanced RXS Router debug mode page to now display instructions to disable debug mode - Enhanced RXS_HTTPResponseDS_t data structure with new subfield ResponseLength to provide the actual length of the response - Enhanced RXSURI command TIMEOUT parameter with new special value *NONE to indicate no maximum timeout - Enhanced HTTP command to allow parameter OPTION values *CONF, *LOGS, *DOCS, *CURLOG, and *DIR to more accurately retrieve the HTTP server path to support HTTP servers created on iASPs - Enhanced BLDPRS command to now include ExtProc(*DclCase) in generated prototypes and procedure interfaces - Enhanced BLDPRS, BLDCMP, and BLDTPL commands to throw an error when the same IFS filepath is provided for both input and output - Corrected an issue with RXS_FormatJson where the RXS_FormatJsonDS_t data structure parameter could become incorrectly reinitialized - Corrected an issue with RXS_ComposeJsonString where passing in an indicator value like RXS_JSON_TRUE or RXS_JSON_FALSE would lead to the JSON containing 16mb of 1s or 0s - Corrected an issue with RXS_PutStdOut where input parameter size was being calculated multiple times - Corrected an issue with CRTRXSSVR command PORT parameter help text displaying the wrong parameter name - Corrected an issue with RXSURI command where output would not be displayed interactively if an input IFS file was used - Corrected an issue with RXSURI where the help text did not accurately reflect all available options - Corrected a typo in error message KTA120B - Updated XML being composed as part of example programs EX3 and FX_EX3 - Removed legacy INSTALL *PGM object from installation ## 3.5.2 - Corrected an issue where an empty LICP file would result in an incorrectly thrown KTE0002 message instead of KTE0001 as intended - Corrected an issue with RXS_ParseDomToDom where the returned RXS_ParseDomDS_t data structure would not be properly initialized if any error occured during the call to RXS_ParseDomToDom - Corrected an issue with WRKRXSRTRE where the environment library being displayed was incorrectly truncated - Corrected an issue with WRKRXSRTRE which could prevent modifying or adding routing entry records - Corrected an issue with RXS_Transmit where a response with charset ISO-8859-1 could be improperly handled in certain circumstances ## 3.5.1 - Enhanced RXS Router to allow up to 250 libraries to be specified for -liblst or -dftliblst - Enhanced WRKRXSRTRE to show the current active mode when displaying, modifying, or deleting a routing entry record - Enhanced WRKRXSRTRE to no longer attempt validation for routing entry records for records with DEBUG as the routing ID - Corrected an issue with library list handling in RXS Router that prevented libraries specified in -liblst or -dftliblst from being added to the library list in certain circumstances - Corrected an issue where RXS Router's debugmode page would truncate routing entry record data for large routing entry records ## 3.5.0 - **The product name has been formally changed to RPG API Express.** This change is purely cosmetic, impacting descriptive text, help panel text, and some message text. This change has no functional impact on the usage of the product. - **The minimum supported operating system version is now IBM i 7.3** ### Code Generation Tools - [New] **New feature:** BLDCMP is a new code generation command that can be passed an IFS JSON file and will generate the appropriate RPG source code which would allow for composing identical JSON using the RXS JSON composition APIs - [New] **New feature:** Added a new optional parameter INCCRTCMD to command CRTRPGTPL which allows a user to omit the section of a generated template that contains the creation command information - Enhanced BLDTPL to preserve namespace attributes when generating templates, rather than converting them to variable placeholders - Enhanced CRTRPGTPL to support whitespace in front of section delimiters - Enhanced CRTRPGTPL to better handle escaping single quotation marks when wrapping lines - Corrected an issue where CRTRPGTPL would generate creation command information where the IFS filepath was truncated - Corrected an issue where CRTRPGTPL would retain a lock on a source member provided as input ### HTTP Communication - RXS_Transmit and RXS_getURI() - [New] **New feature:** Added new subfields HeaderAuthScheme and HeaderAuthCredentials to RXS_TransmitDS_t to allow RXS_Transmit to more broadly support a variety of authentication mechanisms without needing to set custom HTTP headers. This support allows for credentials/tokens up to 8kb in length to better support complex/large JWT tokens when used as part of a Bearer authentication scheme. - [New] **New feature:** Added new subfield HeaderAcceptEncoding to RXS_TransmitDS_t to allow RXS_Transmit to request that the remote server provide gzip encoded response data via the [Accept-Encoding HTTP header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Encoding), and RXS_Transmit will automatically handle decoding. This should result in an overall performance increase when calling any web APIs which support gzip encoding. **Requesting that the remote server provide the response via gzip encoding is now the default behavior** - [New] **New feature:** Added a new constant RXS_TIMEOUT_UNLIMITED to allow setting an unlimited timeout when calling RXS_Transmit - Enhanced RXS_Transmit to allow output to be directed both to a response field as well as to a response IFS file - Enhanced RXS_Transmit IFS log file output to properly display the response when the remote server provided the response using chunked encoding. Previously, the IFS log file would display the response split into chunks along with the chunk encoding length bytes - Corrected a rare issue where RXS_Transmit ending in error with an IFS log file specified could attempt to generate an IFS log file on a subsequent successful RXS_Transmit call which did not request a log file - Corrected an issue with RXS_getURI preventing zero length POST requests ### Encryption and Hashing APIs - [New] **New feature:** Added RXS_HMAC to perform HMAC calculation utilizing the SHA1, SHA256, SHA384, SHA512, and MD5 algorithms ### Offering Web Services/APIs - [New] **New feature:** Added -aspgrp flag to RXS Router to allow for swapping the ASP Group prior to any library list changes or program calls - Enhanced the CRTRXSSVR command to support 5-digit port numbers up to 65535 - Enhanced the CRTRXSSVR command with new *HTTP and *HTTPS options for setting the port number which will cause port 80 and port 443 to be used - Corrected an issue with the HTTP command where a validation message was not properly displayed when attempting to use parameter HTTPSVR(*ALL) with an OPTION other than *WRK, or when attempting to use HTTPSVR(*ADMIN) with an option other than *WRK, *START, *END, or *RESTART ### JSON Composition APIs - Corrected an issue where RXS_GetJsonString could enter a looping condition if certain hexadecimal characters were present in composed JSON data ### JSON Parsing APIs - Enhanced RXS_ParseJson to check input JSON for possible truncation before attempting to parse, and added specific error output to differentiate truncation as a cause of parsing failure from malformed JSON ### XML Parsing APIs - Corrected an issue where RXS_XPath was incorrectly escaping @ symbols that were part of a formatted XPath - Corrected a potential memory leak present in RXS_Parse when parsing XML stored in an IFS file ### Conversion APIs - Enhanced RXS_Convert Base64 and Base64URL decoding to ignore whitespace characters including space, tab, CR, LF, and NL - Corrected an issue with RXS_Convert Base64URL decoding where it would fail on certain string lengths that could not be accurately internally padded - Corrected an issue with RXS_Convert Base64 and Base64URL decoding where line break characters could cause a failed conversion loop ### Example Programs - Included example programs are now provided in two forms - fully free format RPG as well as traditional/fixed format RPG - Included example programs have been updated to reflect our team's latest recommended standards for calling and using various RXS APIs - To provide clarity and work within the 10 character object name limit, existing example programs have been renamed - see table below: | ORIGINAL EXAMPLE NAME | NEW FREE FORMAT NAME | NEW FIXED FORMAT NAME | | --- | --- | --- | | CELSIUS | EX1 | FX_EX1 | | CELSIUSDOM | EX2 | FX_EX2 | | DOMRECUR | EX3 | FX_EX3 | | EXCOMPOSE1 | EX4 | FX_EX4 | | EXPARSE1 | EX5 | FX_EX5 | | XSDVALID | EX6 | FX_EX6 | ### Other Changes - New constants have been added to the RXSCB copybook for commonly used HTTP status codes - Display file CONFIRMD has been renamed to RXSCFMD based on a user-reported conflict with a display file named CONFIRMD present in another vendor's product. The existing CONFIRMD may be safely deleted - Enhanced the DSPMCHINF command to now show the partition UUID in preparation for future licensing enhancements - Enhanced the APYLIC command to no longer interactively prompt for license key replacement when the APYLIC command is run as part of a batch job - Enhanced internal licensing code to reduce unnecessary LICP database file access and reduce necessity of using UPDPROD(*YES) in some situations - Corrected an issue where WRKRXSRTRE would display an incorrect date when run from a long-running job ## 3.4.7 ### Code Generation Tools - Enhanced BLDPRS to allow a base envelope value to be specified when generating XML parsing handlers, allowing for shorter XPaths within the handler subprocedure - Corrected an issue in BLDPRS where code for XML content events would sometimes fail to be generated if some event options were disabled - Corrected an issue preventing errors triggered within CRTRPGTPL from properly propagating to the user, causing cryptic error messaging when the template creation process failed ### JSON APIs - Corrected an issue with the RXS_CreateJson() TrimVariables option incorrectly handling leading whitespace - Corrected an issue where RXS_GetJsonStringLen() was occasionally returning an incorrect and larger value ### Other Changes - The QRPGLECPY,RXSCB copybook is now provided in fully free format RPG. We now also provide a traditional/fixed format RPG equivalent which can be found in QRPGLECPY,RXSCB_FX for RPG developers who are more comfortable with the older RPG code format. Going forward, any changes made to RXSCB will be reflected in RXSCB_FX to the degree that the RPG language allows. RXSCB_FX is intended primarily for reference purposes for developers unfamiliar with fully free format RPG. We don't recommend changing your existing programs to use RXSCB_FX instead of RXSCB, and we don't recommend using RXSCB_FX to write new programs - Corrected an issue that occasionally caused inconsistent Base64 encoding with RXS_Convert() when the provided input field was not a 4-byte varying field - Enhanced RXS_XPath() with better error messaging for when string replacements are specified but there are insufficient provided input parameter values to fill them - Updated RXSURI to be consistent with RXS_Transmit() with regards to trimming input parameters ## 3.4.6 ### Conversion APIs - [New] Added RXS_ConvertBase64UrlDS_t as option to RXS_Convert() to allow for Base64Url encoding/decoding ### HTTP Communication - RXS_Transmit() - Corrected issue with RXS_Transmit() treating HTTP response headers as if they were UTF-8 data instead of ISO-8859-1 as per [RFC 5987](https://tools.ietf.org/html/rfc5987) and [RFC 8187](https://tools.ietf.org/html/rfc8187) - Corrected issue using custom HTTP headers with RXSURI which could result in the custom headers not being sent ### CGI APIs - Corrected issue with RXS_GetUrlVar() that could cause a retrieved URL variable to be truncated instead of retrieved fully ### Code Generation - Corrected issue with CRTRPGTPL resulting in a 3029 error when attempting to use a source member for the input instead of an IFS file ### Other Changes - Corrected issues with internal licensing code which could cause errors when running on partitions with an LPAR ID above 100 ## 3.4.5 ### JSON APIs - Corrected issue with RXS_ComposeJsonNumber() handling of decimal values that failed to include zeros before the decimal point - [New] Added new error message KTA120C to RXS_ComposeJsonNumber() to more clearly indicate when a provided input value was unable to be parsed as a valid JSON number ### CGI APIs - Corrected issue with RXS_PutStdOut() that could cause a "Pointer not set for location referenced" error to occur when providing the optional data structure parameter. This issue was introduced as part of changes made in RXS 3.4.3 ### Other Changes - Removed internal license checks from commonly used subprocedures RXS_STR(), RXS_GetJobCCSID(), and RXS_JobLog() to improve overall performance ## 3.4.4 ### JSON APIs - Corrected issue with using TrimVariables where values composed to child objects/arrays would not be properly trimmed ### RXS_Crypt() - Corrected issue with RXS_Crypt() silently failing when not provided with an algorithm when performing SHA hashing. Error KTA0308 will now be thrown ## 3.4.3 ### HTTP Communication - RXS_Transmit() - Enhanced RXS_TransmitDS_t data structure subfield array CustomHeaderValue to increase the size from 1KB to 4KB to allow for longer custom headers when calling RXS_Transmit() - Enhanced RXS_HTTPResponseDS_t data structure subfield array HeaderValue to increase the size from 1KB to 4KB to allow retrieving longer headers from the response - Updated RXS_TransmitDS_t data structure subfield array HeaderCookieFiles to decrease the number of array elements from 50 to 10. This change was based on customer feedback and should help reduce total memory usage ### JSON APIs - Updated RXS_ComposeJsonBoolean() to properly treat values other than RXS_JSON_TRUE or RXS_JSON_FALSE as invalid input rather than treating anything other than RXS_JSON_TRUE as 'false'. A KTA120B error will now be thrown when invalid input is provided to RXS_ComposeJsonBoolean() ### Template Variables and Constants - [New] Added new RXS_Var4K_t varying 4KB template variable to RXSCB - [New] Added new RXS_Var1M_t non-varying 1MB template variable to RXSCB ### Other Changes - Modified RXS_ResetDS() to increase parameter size to allow for larger data structures - Corrected text description of `-prdlib` flag in WRKRXSRTRE help text ## 3.4.2 ### HTTP Communication - RXS_Transmit() - Enhanced RXS_TransmitDS_t data structure with new subfield FollowRedirects to control if RXS_Transmit() will automatically follow HTTP 3XX status code redirects. The default value is `RXS_YES` to maintain compatibility with prior releases - Enhanced RXS_Transmit() logfile output to indicate that SSLCertStore will use the *SYSTEM certificate store by default ### JSON APIs - Enhanced RXS_CreateJsonDS_t with new subfield TrimVariables to control if RXS_ComposeJsonString() will trim excess whitespace from composed JSON values. The default value is `RXS_NO` to maintain compatibility with prior releases - Corrected issues that could occur when passing JSON names as fields instead of literals when composing JSON - Corrected issue with RXS_CreateJson() that could cause an `KTA120A: RXS_CreateJson() was provided an invalid data structure parameter` error when using `/DEFINE RXSV6R1` ### STMF APIs - Corrected issue with RXS_PutStmf() silently failing when not provided with a filepath ### XML Composition APIs - [New] Added RXS_GetComposeBufferLen() API based on customer feedback. This API can be used to retrieve the current length of the compose buffer similar to the functionality of RXS_GetJsonStringLen() ### Other Changes - Corrected text description of PORT parameter on CRTRXSSVR command ## 3.4.1 ### RXS Router - Corrected issues preventing RXS Router `-passwd` flag from working correctly when the QPWDLVL system value was set to 2 or 3 - Enhanced RXS Router `-passwd` flag to support passwords up to 128 characters and removed character restrictions - Enhanced `-passwd` flag for RXS Router to support `*NOPWD`, `*NOPWDSTS`, and `*NOPWDCHK` to allow profile swapping to IBM i user profiles with their password set to `*NONE` - Enhanced RXS Router to send a message to the CGI joblog on start to show which version of RPG-XML Suite is being used - Enhanced RXS Router debug report page to show which version of RPG-XML Suite is being used ### HTTP Communication - RXS_Transmit() and RXS_getUri() - Updated RXSURI command to internally call RXS_Transmit() instead of RXS_getUri(). The log file generated by RXSURI now reflects the RXS_Transmit() log format as a result - Updated default values specified in the RXSURIP file used by the RXSURI command. Requests will now use HTTP 1.1 and CCSID 1208 by default. These values replace the defaults of HTTP 1.0 and CCSID 819 used in previous versions - Corrected issue which could cause intermittent SSL timeout errors to appear in the RXS_Transmit() log file in rare cases ### RXS_Crypt() - [New] Added support for AES-128, AES-192, and AES-256 encryption to RXS_Crypt() ### RXS_Convert() - Corrected issue with unexpected output when using RXS_Convert() to perform URL percent encoding where multibyte characters were present - Enhanced RXS_ConvertURLPercentDS_t with two new subfields, InputCCSID and OutputCCSID, both of which are defaulted to the CCSID of the current job - Corrected issue which could occur rarely when using RXS_Convert() to perform CCSID conversion with empty input ### JSON APIs - Corrected issue with how the JSON compose APIs handle CCSID conversion of some non-printable characters to UTF-8, which could result in incorrect output of multibyte characters after conversion ### XML Composition APIs - Corrected issue introduced in 3.4.0 which could cause RXS_GetComposeBuffer() to retain previously retrieved composed data ### XML DOM Parsing APIs - Corrected issue with the RXS3 DOM APIs which could prevent loading XML documents larger than 4MB ### XML Event Parsing APIs - Corrected issue introduced in 3.4.0 which caused RXS2 RXS_parse() error messages to be partially returned in an incorrect CCSID ## 3.4.0 - **The minimum supported operating system version is now IBM i 7.1** - RPG-XML Suite's version number now uses the format MAJOR.MINOR.PATCH to be more in line with commonly used semantic versioning standards - The RXS 2 and RXS 3 APIs are no longer separately versioned as they were in previous releases. Output provided by the DSPVER and DSPMCHINF commands as well as the VERRXSBASE program will now only report a single version number ### Example Programs - Example source code for the RXS 2 APIs is no longer provided in the included EXAMPLE source physical file. We recommend all new applications are written using the RXS 3 APIs. Example code for the RXS 3 APIs has been moved to the EXAMPLE source physical file - Example programs are no longer provided in a compiled state during the installation. This change was made based on customer feedback ### RXS 2 Copybook - The RXSCP copybook containing the RXS 2 API prototypes, data structures, and constants which was previously located in the included RXS source physical file has been moved to the included QRPGLECPY source physical file. Existing programs using the RXS 2 APIs will continue to work without modifications, but before any future recompilation you will need to change the `/copy RXS,RXSCP` line in your programs to be `/copy QRPGLECPY,RXSCP` ### HTTP Communication - RXS_Transmit() and RXS_getUri() - Changed RXS_Transmit() and RXS_getUri() to use the IBM GSKit SSL APIs for SSL/TLS communication. This allows for SNI support and other improved capabilities. Note that this may cause RXS_TransmitDS_t.SSLVerifyPeer and RXS_TransmitDS_t.SSLVerifyHost subfields to no longer ignore missing/invalid SSL certificates in all circumstances, and you may begin receiving errors as a result after upgrading. If you do, you should [install the SSL certificates](https://isupport.katointegrations.com/rxs/installing_certificate_authorities.md) for the endpoint you are calling - Corrected issues with RXS_Transmit() which could cause a generated log file to be empty - Enhanced the RXS_TransmitDS_t data structure to include a new LocalInterface subfield. LocalInterface can be set to an IP address. When set to an IP address, RXS_Transmit() will use this value to determine the proper network interface to use. - Enhanced the RXS_TransmitDS_t data structure to include a new EnableIPv6 subfield. EnableIPv6 can be set to RXS_YES or RXS_NO (default: RXS_NO). When set to RXS_YES this option will allow RXS_Transmit() to resolve a host name to either the IPv4 or IPv6 address instead of being limited to only resolving to the IPv4 address. - Corrected issue with RXS_Transmit() when performing a HTTP DELETE operation - Corrected issue preventing RXSURI command from properly sending custom HTTP headers in some circumstances ### JSON APIs - Enhanced JSON parsing and composing API internal code, which corrects a number of issues with memory usage and CCSID handling as well as JVM conflicts. Any existing programs that are parsing or composing JSON should perform substantially better - Previously, the JSON APIs relied on files in the IFS stored in a /krengeltech directory. This directory is no longer required starting with RXS 3.4.0 and can be safely removed - Calling RXS_DestroyJson() is no longer required after RXS_ParseJson(). RXS_DestroyJson() now only needs to be called on the RXS_CreateJsonDS_t that was originally used in a call to RXS_CreateJson(). Existing code which calls RXS_DestroyJson() after RXS_ParseJson() will continue to function without any changes or recompilation required, but we recommend reviewing your code to remove any unnecessary RXS_DestroyJson() calls - [New] Added RXS_FormatJson() API based on customer feedback. This API can be used to format a JSON document or STMF to either minify the document, or to expand it and control indentation and whitespace - [New] Added RXS_GetJsonStringLen() API based on customer feedback. This API will return the length of character field needed to store the JSON document composed in the provided RXS_CreateJsonDS_t - Enhanced JSON APIs to support duplicate keys within objects per JSON RFC 7159 - Enhanced RXS_ComposeJsonString() to allow *Omit for parameter 2. *Omit is treated as equivalent to passing a 0 length empty string - Enhanced error messages for all RXS JSON composition and parsing APIs to provide more detail - Enhanced validation for RXS_ParseJson() settings. As a result, programs that are calling RXS_ParseJson() without specifying a parsing handler will now throw error message KTA1207 - Enhanced validation for input provided to RXS_ParseJson(). As a result, programs that are calling RXS_ParseJson() and providing an empty JSON document will now throw error message KTA1208 - Corrected issue when using RXS_ParseJson() to parse a JSON document which contained empty child JSON objects ### XML Composition APIs - Enhanced the RXS_ComposeDS_t data structure to include a new TrimVariables subfield. TrimVariables can be set to RXS_YES or RXS_NO (default: RXS_NO). When set to RXS_YES this option will cause RXS_ComposeVariable() to remove all leading and trailing whitespace from the passed value equivalent to if the value had been wrapped by the RPG %Trim() built-in function - Enhanced the RXS_ComposeDS_t data structure to include a new EncodeVariables subfield. EncodeVariables can be set to RXS_YES or RXS_NO (default: RXS_NO). When set to RXS_YES this option will cause RXS_ComposeVariable() to encode all XML reserved characters (`&` `'` `"` `>` `<`) with the appropriate entities (`&` `'` `"` `>` `<`) in the passed value - Enhanced RXS_ComposeVariable() to allow `*Omit` to be passed for parameter 2. `*Omit` is treated as equivalent to passing a 0 length empty string - Corrected issue preventing RXS_ComposeVariable(), RXS_ComposeSection(), and RXS_GetComposeBuffer() from throwing an error when RXS_StartComposeEngine() had not previously been called ### RXS_Convert() - Corrected issue when using RXS_Convert() to encode XML entities that could lead to a memory leak in certain scenarios - Corrected issue causing RXS_Convert() to throw an error when provided with an empty character field for input ### RXS_Crypt() - Corrected issue preventing `*Omit` from being used as the first parameter for RXS_Crypt() - Corrected issue with RXS_Crypt() MD5 and SHA hashing memory usage and IFS file access ### Code Generation - Enhanced the BLDPRS command to support generating RXS 2 XML parsing code, RXS 3 XML parsing code, or JSON parsing code. BLDPRS can now also generate either mixed or column-limited full free format RPG. As part of this update, the names of some existing parameters were changed and new parameters were added - Enhanced the BLDTPL command to provide better CCSID handling and performance. As part of this update, the names for some parameters have been changed - Enhanced the BLDTPL command to no longer remove the XML prolog during template generation based on customer feedback - Enhanced the CRTRPGTPL command to write a comment section in the generated template member that contains the full command used to generate the template for future reference ### Other Changes - [New] Added RXS_RenameStmfDS_t as option to RXS_ProcessStmf() to allow for easier IFS file renaming - Corrected intermittent error message caused by RXSRTR appearing in Apache job log - Corrected issue preventing RXS_GetUrlVar() from handling empty URL variables properly - All included commands now provide help via included *PNLGRP objects ## 3.36 - Internal changes to allow initial SNI support. ## 3.35 - Corrected an issue with ScriptAliasMatch directives when building a new httpd.conf file. ## 3.34 - RXS_Convert() now works properly when URL encoding/decoding strings over 64K ## 3.33 - RXS_GetJsonString() now works properly in all situations with JSON prettification disabled. - RXS_RESETDS() now works correctly with RXS_CreateJsonDS_t, RXS_JsonStructureDS_t, RXS_ParseJsonDS_t - RXS_GetEnvVar() now correctly returns an empty string for variables which do not exist - RXS_Parse() no longer requires programs compiled under v3.31 or earlier to be recompiled to avoid a decimal data error. This affected only programs running under v3.32 after last being compiled with v3.31 or earlier. ## 3.32 - RXS_ResetDS() now supports: RXS_DS_TYPE_CREATEJSON, RXS_DS_TYPE_JSONSTRUCTURE and RXS_DS_TYPE_PARSEJSON - RXS_GetStdIn() now properly handles binary output to a stream file - Performance enhancements to RXS_Parse() - Performance enhancements to RXS_ComposeVariable() and RXS_ComposeSection() - Improvements to RXS_OpenDom() to prevent XML declarations from conflicting with the DOM parser's internal character set handling - Improvements to error handling in RXS_Throw() and RXS_Catch() - Improved memory handling and performance in RXS_Convert() - Improvements to error reporting in RXS_OpenDom(), RXS_Parse() and RXS_Convert() - Improvements to RXS_GetUrlVar() and RXS_GetStdIn() when processing URL encoded content - Improved BLDTPL to output variable names that conform to RPG's naming rules - Performance enhancements to speed licensing functions - RXS_ParseJson() prototype changed to use Const instead of Value. **All programs parsing JSON will need to be updated and recompiled.** ## 3.31 - Improved error reporting when parsing a JSON string with incorrect syntax - Improved error reporting when processing JSON without authority to required IFS objects - Correction to RXS_ComposeJsonBoolean() so that composed values are correct - Improved memory handling when composing very large XML strings - Improved performance when parsing large stream files - Improved support for calling non-CGI programs from RXSRTR function ## 3.30 - [New] Added JSON parsing API [RXS_ParseJson()](https://isupport.katointegrations.com/rxs/3.3/rxs_parsejson.md) - [New] Added JSON composition APIs: - [RXS_CreateJson()](https://isupport.katointegrations.com/rxs/3.3/rxs_createjson.md) - [RXS_DestroyJson()](https://isupport.katointegrations.com/rxs/3.3/rxs_destroyjson.md) - [RXS_ComposeJsonNull()](https://isupport.katointegrations.com/rxs/3.3/rxs_composejsonnull.md) - [RXS_ComposeJsonString()](https://isupport.katointegrations.com/rxs/3.3/rxs_composejsonstring.md) - [RXS_ComposeJsonBoolean()](https://isupport.katointegrations.com/rxs/3.3/rxs_composejsonboolean.md) - [RXS_ComposeJsonNumber()](https://isupport.katointegrations.com/rxs/3.3/rxs_composejsonnumber.md) - [RXS_ComposeJsonObject()](https://isupport.katointegrations.com/rxs/3.3/rxs_composejsonobject.md) - [RXS_ComposeJsonArray()](https://isupport.katointegrations.com/rxs/3.3/rxs_composejsonarray.md) - [RXS_GetJsonString()](https://isupport.katointegrations.com/rxs/3.3/rxs_getjsonstring.md) ## 3.22 - Corrected a problem with multi-byte characters in request data causing a false timeout condition when calling RXS_Transmit() - Corrected a problem with multi-byte characters in XML data causing RXS_Validate() to fail when it should have been successful - Changes to the Compose engine to correctly handle repeating data when using the OmitUncomposedLines option with multiple calls to RXS_ComposeSection() - Improvement to RXS_ComposeVariable() to allow `*BLANKS` to be passed on the second parameter, without composing 16MB's of blanks/spaces and instead the composed content will be the same as if a zero length value had been passed ## 3.21 - Corrected an issue that required programs using RXS_Transmit() to be recompiled. Recompiling is no longer needed - Improvements to CRTRPGTPL to better handle templates that have invalid formatting or characters that are not allowed in RPG variables names ## 3.20 - RESTful HTTP Methods such as PUT, DELETE, HEAD, OPTIONS and PATCH (POST and GET continue to be available) - Easy parsing of content from RESTful URI’s such as http://www.example.com/customer/53874 - Support for dynamic as well as compiled templates - Extended length templates up to 256K - Automatic compression of whitespace when composing from templates - Automatic omission of uncomposed template content - New function RXS_ResetDS() for easily initializing data structures used by the RXS3 API - Enhanced RXS_GetStmf() to allow easy reading of stream file content in “chunks” within a loop - Enhanced RXS_PutStdOut() for easy output of HTTP Status, Content Type and other HTTP headers - Extended support for very large XML stream files when using the event based parser - Improvements to CRTRPGTPL command - Read STDIN over 16MB directly to a stream file - Output large stream files over 16MB in size to STDOUT - Improved logging from RXS_Transmit() - Improved RXS_Transmit() when using Basic Authority so that only one request is made to the remote server - Improved STMF handling to inherit authority from the host directory when creating new STMFs ## 3.11 - Introduced [RXS_Validate()](https://isupport.katointegrations.com/rxs/3.1/rxs_validate.md) for use with XSD Validation ## 3.10 - Full support for XPath 1.0 compliant Parsing - [New] Added DOM parsing APIs: - [RXS_OpenDom()](https://isupport.katointegrations.com/rxs/3.1/rxs_opendom.md) - [RXS_CloseDom()](https://isupport.katointegrations.com/rxs/3.1/rxs_closedom.md) - [RXS_ParseDomToText()](https://isupport.katointegrations.com/rxs/3.1/rxs_parsedomtotext.md) - [RXS_ParseDomToXml()](https://isupport.katointegrations.com/rxs/3.1/rxs_parsedomtoxml.md) - [RXS_ParseDomToDom()](https://isupport.katointegrations.com/rxs/3.1/rxs_parsedomtodom.md) ## 3.00 - **The minimum supported operating system is now IBM i 6.1** - Completely new RXS3 API introduced. This API has been redesigned from the ground up and hands the RPG developer an even more powerful tool. - Full support for 16 MB in-memory variables - Base 64 encoding - Full UTF-8 support and improved CCSID handling - Enhanced data security ## 2.88 - Improved compatability with proxy configuration in previous versions. - Improved availability of joblog messages in CGI jobs running via RXSRTR and also using activation groups ## 2.87 - Expanded number of variables allowed in one section of a template - Allowing only IPv4 when using RXS_getUri(). IPv6 will require use of RXS_Transmit() ## 2.86 - Resumed support for LocalIP and LocalPort settings when calling RXS_getUri() - Improved backwards compatability when using RXS_getUri() with HTTP Get method ## 2.85 - Improved support for conversion of XML entities during parsing ## 2.84 - Improved parsing of content that contains XML entities in combination with multi-byte character sets such as UTF-8 - New options for RXS_getUri() that allow host and peer verification to be turned off ## 2.83 - Improved STMF handling to inherit authority from the host directory when creating new STMF's - Improved RXS_getUri() to handle URI's that do not start with http or https - Improved RXS_getUri() when using Basic Authority so that only one request is made to the remote server ## 2.82 - Improvements to CCSID handling when outputting to existing stream files with multi-byte character sets ## 2.81 - Correction to template engine when outputing stream files encoded as UTF-8 or other multi-byte character sets ## 2.80 - Enhancements to BLDPRS command - Ignore default namespaces in DOM parser unless DOM_INCNSATR set as an option - Updates to HTTP client to correct output to debug files when multiple communications are transmitted - Created RXSMENU, DSPVER, DSPLIC and APYLIC commands for menu driven version and licensing tasks - Seperate licensing library KTLIC no longer required ## 2.71 - Enhancement to allow multiple members in RXSCFG to allow member names to reflect RXSRTR environment names when desired. (The RXSCFG member is the default when RXSRTR is not in use or a member matching the environment name is not found.) - When creating Apache instances, changed logs directory authority to `*RWX` - Licensing updates for certain IBM serial numbers and for BLDTPL and BLDPRS commands ## 2.70 - **The minimum supported operating system is now IBM i V5R4** - Enhancements to RXS Router allowing single library installation for simplified configuration and streamlined upgrades. - Improved CCSID handling to support character sets outside of North America - Various performance improvements and bug fixes - New licensing system - New [RXS_getUri()](https://isupport.katointegrations.com/rxs/2.x/rxs_geturi.md) communications client ## 2.51 - Correction to allow case insensitive XPath's when using the DOM parser ## 2.50 - Enhancements to RXS Router allowing single library installation for simplified configuration and streamlined upgrades. Improved CCSID handling to support character sets outside of North America ## 2.40 - Fixed bug in DOM parser to intialize storage used in previous parses - Improved limits in DOM parser allowing increased element count in parsed XML - Enhanced RXS Router to allow mixed case for RXSRTRCTL option switches - Fixed bug in [RXS_getUrlVar()](https://isupport.katointegrations.com/rxs/2.x/rxs_geturlvar.md) to allow encoded ampersands to be decoded correctly (%26) - Enhancement to [RXS_getUrlVar()](https://isupport.katointegrations.com/rxs/2.x/rxs_geturlvar.md) to decode percent encoded characters correctly when CGIConvMode is set to MIXED - Fixed parser bug to allow UTF-8 double-byte characters in attribute data ## 2.30 - Fixed bug in [RXS_getUrlVar()](https://isupport.katointegrations.com/rxs/2.x/rxs_geturlvar.md) when the last variable's value in QUERY_STRING was a single character. - Fixed bug where [RXS_getUrlVar()](https://isupport.katointegrations.com/rxs/2.x/rxs_geturlvar.md) was returning the **&** char in the event of an empty QUERY_STRING variable. ## 2.20 - Enhancement: Options used when calling [RXS_DOMSetOpt()](https://isupport.katointegrations.com/rxs/2.x/rxs_domsetopt.md) or [RXS_DOMBuild()](https://isupport.katointegrations.com/rxs/2.x/rxs_dombuild.md) have been simplified. - Fixed bug: Modified the template engine to ignore other forms of whitespace at the end of sections names. Previously, if invisible characters existed due to copying template code from Word or PDF documents, the section name would not be detected properly and would require the template to be modified. - Modified RXS Router added in v2.10 to exist in base RXS library, rather than a separate library. - Modified RXS Router command INZRXSRTR to be executable by users with authority to RXSRTRCTL and INZRXSRTR. - Modified RXS Router httpd.conf to allow multiple types of CGI invocations. This allows you to configure URLs which bypass the router if needed. - Fixed bug where DOM Parser functions [RXS_DOMGetData()](https://isupport.katointegrations.com/rxs/2.x/rxs_domgetdata.md) and [RXS_DOMGetDataCount()](https://isupport.katointegrations.com/rxs/2.x/rxs_domgetdatacount.md) would return incorrect values when using repeating elements. - Fixed bug where sometimes during install, data area RXSBASE was not being given appropriate authority, and would falsely report that an RPG-XML Suite license key was invalid immediately after installation. ## 2.10 - NEW FEATURE: Added new "RPG-XML Suite Router" functionality. This will ease the offering of web services as it takes care of altering the library list and user profile before your web service is invoked. - NEW FEATURE: RXS HTTP Command to make it easier, and safer, to end, start, and configure your Apache server instances. - Enhancement: When processing template files (i.e. IFS .tpl files), the section names will have `*Blanks` trimmed from the end of their name. Previously, if blanks existed, the template engine wouldn't consider the name and the .tpl would have to be modified. - Enhancement: Allow [RXS_getEnvVar()](https://isupport.katointegrations.com/rxs/2.x/rxs_getenvvar.md) to be called multiple times. Normally in the case of GET based web services there has been a single URL parameter named "xml" that would contain the inbound XML. With RESTFul web services making a mark in the web services world we have expanded the RXS_getEnvVar() API to facilitate multiple calls for differently named variables. - Enhancement: Traditionally when there were unmatched delimiters in a template file (i.e. IFS .tpl files) it would throw a MCH0603 error. Now a more informative message will be relayed to the job log. - Enhancement: Speed improvements have been made in the RXS_DOM* based parsing API's. ## 2.00 - NEW FEATURE: Added DOM features for simplified parsing of XML documents. New APIs include: - [RXS_DOMBuild()](https://isupport.katointegrations.com/rxs/2.x/rxs_dombuild.md) - [RXS_DOMGetData()](https://isupport.katointegrations.com/rxs/2.x/rxs_domgetdata.md) - [RXS_DOMGetDataCount()](https://isupport.katointegrations.com/rxs/2.x/rxs_domgetdatacount.md) - [RXS_DOMCleanup()](https://isupport.katointegrations.com/rxs/2.x/rxs_domcleanup.md) - [RXS_setXPath()](https://isupport.katointegrations.com/rxs/2.x/rxs_setxpath.md) - [RXS_getXPath()](https://isupport.katointegrations.com/rxs/2.x/rxs_getxpath.md) ## 1.42 - Fixed bug where RXSCFG was being read for each call to RXS_getUri() or RXS_initTplEng() and now it is just called the first time in each job and then the data is cached to better performance. - Fixed bug that was causing issues when RXS was used in conjunction with DDM files or RPG being front ended by stored procedures. This was a bug that affected few customers in very specific usage scenarios. ## 1.41 - Modified RXS_getUri() to use 65535 VARYING vs. 65535 without VARYING. This addresses issues when trying to pass by reference and not having the exact same string type. - RXSCP fields RXS_getUriOut, RXS_getUriHead, and RXS_getUriData have been deprecated and commented out. They will be physically removed from RXSCP in v1.5. If you had version 1.4 installed you will need to recompile your programs to use this latest version. - Modified RXS_getUri() to default to port 443 if port is 0 and SSL=RXS_YES was specified. ## 1.40 - NEW FEATURE: RXS_setParseEnc() - NEW FEATURE: RXS_ignElemNamSpc() - Modified commands BLDPRS and BLDTPL to better handle long XPaths - Modified default delimiters to be `::` for section names and `.:var:.` for variable names. In previous versions they were `/$` for section names and `/%var%/` for variable names. This was changed for variety of reasons with the biggest being usage in foreign countries. By using colons and periods the code can be typed faster for manual modification of templates. If you are upgrading you should do an UPDDTA RXSCFG and change the defaults to `/$` for section begin delimiter, `/%` for var begin delimiter and `%/` for var end delimiter. ## 1.30 - NEW FEATURE: Added RXS_addLibLE() - NEW FEATURE: Added RXS_libLEExists() - NEW FEATURE: Added RXS_rmvLibLE() - NEW FEATURE: Added RXS_getBuffLen() to get a count of bytes in the Template Engine buffer to know if it is over 65535 and thus to big to retrieve with RXS_getBuffData(). - NEW FEATURE: Added RXS_getBuffData() to get the Template Engine data that is currently buffered so it can be put into a 65535 VARYING field and used on RXS_getUri(). - Changed HTTPD.txt to not use $ signs (also changed NEWENV command) - Fixed bugs in BLDPRS that were making it not work right with long xPaths. - [New] Added delim fields to RXSCFG - Changed RXS_initTplEng() to operate off of default delimiters in RXSCFG and change default delimiters in program to not be constants. - Changed RXS_updVar() to be able to do 65535 varying, was set at 1024 at an inner level of code. - Enhancing RXS_soapDecode() for speed and accuracy. - Adding code to BLDPRSR and BLDTPLR to not delete user index unless it exists. It was putting messages in job log uncessarily - [New] Added DftTransDir to RXS_readToFile() if no path was specified. - [New] Added DftTransDir to RXS_outFromFile() if no path was specified. - [New] Added DftTransDir to RXS_deleteFile() if no path was specified. - When using RXS_readToFile() extra spaces were sometimes added to the end of the files contents. This has been addressed to not have additional spaces. - Change error text in RXS_cmpTransFile() to be RXSCFG instead of CONFIG. - [New] Added defaults for RXS_getUri(): This will save typing when using RXS_getUri() as not as many data structure fields will need to be filled. - ds.ReqType=RXS_POST - ds.SprHead=RXS_YES - ds.Debug=RXS_NO - ds.RspType=RXS_VAR - ds.ReqType=RXS_VAR - ds.ContType='text/xml' - When a POST with zero content is sent and RXS_readToFile() is used an error was inappropriately thrown. Now no error is thrown. - Changed RXS_readToFile() to truncate content on IFS open. - Changed RXS_getUriOut and RXS_getUriHead from 32767 to 65535 in RXSCP (main RXS copybook) - [New] Added field RXS_getUriData to RXSCP in relation to new RXS_getUri() functionality - Changed RXS_getUri() to be able to send and receive 65535 bytes of data if not using IFS files. Previous limitation was 2048. - [New] Added new OutType of RXS_VAR to RXS_initTplEng(). This should be used in conjunction with RXS_getBuffData(). - **!!RECOMPILE!!** Changed RXS_getUri() to have the second, third and newly added forth parms as `OPTIONS(*OMIT)` for ease of use (so you don't have to specify them if you aren't using them) - [New] Added example TPLENG3 to show how to use RXS_getBuffData(). - The field RXS_GetUriHead (i.e. response HTTP Headers) will always be returned when a variable is specified vs. only being returned when SprHead (Seperate Headers) is specified. This pertains to RXS_getUri(). - Modified client app Web Service Tester to save responses to a stream file and retain URLs that have been accessed. ## 1.20 - Renamed RPG-XML Suite config PF, MYRXS/CONFIG, to MYRXS/RXSCFG. - Changed RXS_parse() to `%TRIM` input file name - Changed RXS_parse() to throw an error if file to parse doesn't exist. - [New] Added RXS_soapDecode() - Increased RXS_updVar() input to 65535. - Changed RXS_initTplEng() to `%TRIM` out file name - [New] Added example GETURI4 to show Template Engine overriding of sections/variables and also ability to override event handler type values. - [New] Added RXS_charToTimestamp() - [New] Added RXS_timestampToChar() - [New] Added RXS_charToBln() - Modified RXS_charToNbr() to have default value parameter. - [New] Added parsing code generator BLDPRS(Build RPG Parsing Subprocedure) - [New] Added template generator BLDTPL (Build Template) - [New] Added RXS_getUri() PUser and PPW (Proxy User and Proxy Password) - [New] Added DSPMCHINF for ease of displaying machine information. ## 1.10 - Changed RXS_loadTpl() to allow overriding abilities for section and variable delimiters. For internationalization purposes. - Changed RXS_parse() to allow the passing of handler event type value overrides (i.e. ELEMBEGIN, ELEMCONTENT, ELEMEND, ATTR). For internationalization purposes. - [New] Added example RXS6 to show Template Engine overriding of sections/variables and also ability to override event handler type values. - Modified install *SAVF to be V5R1 instead of V5R3 ## 1.00 - Initial release. --- # RXS_Catch() > Catches an RXS exception thrown by RXS_Throw(), returning error details for structured error handling. This subprocedure can be used to catch an error thrown by [RXS_Throw()](https://isupport.katointegrations.com/rxs/3.2/rxs_throw.md) or via other methods. The error information is retrieved into a RXS_CatchThrowErrorDS_t data structure. Typical usage involves this subprocedure being called inside the ON-ERROR section of a MONITOR group. ## Subprocedure Prototype ### IBM i 6.1+ ```rpgle // Returns RXS_CatchThrowErrorDS_t data structure containing the error // information that was previously thrown. D RXS_Catch... D PR Extproc('RXS_Catch') D Likeds(RXS_CatchThrowErrorDS_t) ``` ## Example Code ### IBM i 6.1+ #### Example 1: Catch Error ```rpgle *-------------------------------------------------------------- * This example demonstrates calling RXS_Catch() and assigning the return * value to a RXS_CatchThrowErrorDS_t datastructure. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*NEW) /COPY QRPGLECPY,RXSCB D ErrorDS DS LikeDS(RXS_CatchThrowErrorDS_t) D Inz(*LikeDS) D NumA S 10I 0 D NumB S 10I 0 D Result S 10I 0 /FREE monitor; // To ensure we trigger an error, we're going to divide by 0. NumA = 5; NumB = 0; Result = NumA / NumB; on-error; // Note that you don't have to use RXS_ResetDS to initialize ErrorDS before // using it - this is one of the few RXS data structures where // this is safe and correct. ErrorDS = RXS_Catch(); // At this point ErrorDS should contain the error information for an // MCH1211 "divide by zero" error. endmon; return; /END-FREE ``` ## Data Structures ### RXS_CatchThrowErrorDS_t ```rpgle D RXS_CatchThrowErrorDS_t... D DS Qualified Template Inz // The message ID that was received. D MessageId 7A // The message file used to store the message ID. D MessageFile 20A // The message data to be merged with the text of the message ID. D MessageData 1024A Varying D DataStructureType... D 5I 0 Inz(RXS_DS_TYPE_CATCHTHROWERROR) // The type of message that was sent. // Valid values: RXS_MESSAGE_TYPE_DIAG, RXS_MESSAGE_TYPE_COMP, // RXS_MESSAGE_TYPE_INFO, RXS_MESSAGE_TYPE_INQ, RXS_MESSAGE_TYPE_RQS, // RXS_MESSAGE_TYPE_NOTIFY, RXS_MESSAGE_TYPE_ESCAPE, // RXS_MESSAGE_TYPE_STATUS D MessageType 5I 0 // The full message text that combines the value of the message ID's text // and the merged message data. D MessageText 4096A Varying // Not used. Used by RXS_Throw() only. D ThrowToCaller... D N Inz(RXS_NO) ``` --- # RXS_CloseDom() > Frees memory allocated by RXS_OpenDom(); must be called once DOM parsing is complete. This subprocedure is used to clean up after utilizing the DOM parsing API [RXS_OpenDom()](https://isupport.katointegrations.com/rxs/3.2/rxs_opendom.md). It only needs to be called on the primary DOM data structure. You should not attempt to close a DOM data structure created as a result of calling RXS_ParseDomToDom(). This subprocedure must be called at the end of all DOM parsing to properly free up memory and avoid performance impacts. ## Subprocedure Prototype ### IBM i 6.1+ ```rpgle D RXS_CloseDom PR Extproc('RXS_CloseDom') Opdesc // The RXS_ParseDomDS_t data structure previously initialized and used as // part of RXS_OpenDom() D DS Like(RXS_ParseDomDS_t) D Options(*Varsize) ``` ## Example Code ### IBM i 6.1+ #### Example 1 ```rpgle *-------------------------------------------------------------- * This example demonstrates closing DOM parsing using a RXS_ParseDOMDS_t * datastructure. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB D OpenDomDS DS LikeDS(RXS_OpenDOMDS_t) D RootDomDS DS LikeDS(RXS_ParseDOMDS_t) /free RXS_ResetDS( OpenDomDs : RXS_DS_TYPE_OPENDOM ); RXS_ResetDS( RootDomDs : RXS_DS_TYPE_PARSEDOM ); OpenDomDs.InputCcsid = RXS_CCSID_UTF8; RootDomDS = RXS_OpenDom( gXmlResponse : OpenDomDs ); gXPath = RXS_XPath( '/*:Envelope/*:Body/*:FahrenheitToCelsius' + 'Response/*:FahrenheitToCelsiusResult' ); gCelsius = %Dec( RXS_ParseDomToText( gXPath : RootDomDS ) : 11 : 7 ); RXS_CloseDom( RootDomDS ); *INLR = *ON; /end-free ``` ## Data Structures ### RXS_ParseDomDS_t ```rpgle D RXS_ParseDomDS_t... D DS Qualified Template Inz D ReturnedErrorInfo... D LikeDS(RXS_ReturnedErrorInfoDS_t) Inz D OnErrorMessageType... D 10I 0 // Specifies the CCSID of the XML being parsed. D InputCcsid... D 10I 0 // Specifies the CCSID the parsed data will be converted to. D OutputCcsid... D 10I 0 // Specifies an IFS path to an XML file to parse instead of the Input parm. D Stmf... D Like(RXS_Var1Kv_t) // Contains the current count of XML nodes tracked by this data structure. D NodeCount 10U 0 D NodeType 10I 0 // Internal use only D xml@ * // Internal use only D doc@ * // Internal use only D context@ * // Internal use only D dict@ * // Internal use only D current@ * // Internal use only D parent@ * // Internal use only D Reserved 4096A ``` --- # RXS_ComposeSection() > Renders a named section from a loaded template, appending the output to the compose buffer. This subprocedure writes the named section to the compose engine buffer. **Note**: This procedure will throw an error if it has been called without the composition engine being initialized via [RXS_StartComposeEngine()](https://isupport.katointegrations.com/rxs/3.2/rxs_startcomposeengine.md). ## Subprocedure Prototype ### IBM i 6.1+ ```rpgle D RXS_ComposeSection... D PR Extproc('RXS_ComposeSection') // The name of the section to be written to the template engine buffer. D Section 50A Varying ``` ## Example Code ### IBM i 6.1+ #### Example 1 ```rpgle *-------------------------------------------------------------- * This example demonstrates calling RXS_ComposeSection() to write the template * section 'content'. This section would be defined in the XML template EXAMPLE * like so: * ::content * ... *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB /copy QRPGLETPL,EXAMPLE /free RXS_ComposeSection( content ); *INLR = *ON; /end-free ``` --- # RXS_ComposeVariable() > Substitutes a named variable placeholder in the current template section with a supplied value. This searches the currently loaded template for the specified Variable, and replaces it with the Value parameter. If variable is used multiple times, all occurrences will be replaced. **Note**: This procedure will throw an error if it has been called without the composition engine being initialized via [RXS_StartComposeEngine()](https://isupport.katointegrations.com/rxs/3.2/rxs_startcomposeengine.md). ## Subprocedure Prototype ### IBM i 6.1+ ```rpgle D RXS_ComposeVariable... D PR Extproc('RXS_ComposeVariable') // The name of the variable to be replaced in the currently loaded // template. D Variable 30A Varying // The value which will replace the specified Variable. D Value Const Like(RXS_Var16Mv_t) ``` ## Example Code ### IBM i 6.1+ #### Example 1 ```rpgle *-------------------------------------------------------------- * This example demonstrates calling RXS_ComposeVariable() to assign the * value of the gFahrenheit field to the template variable 'fahrenheit'. * This variable would be defined in the XML template EXAMPLE like so: * .:fahrenheit:. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB /copy QRPGLETPL,EXAMPLE D gFahrenheit S 3P 1 /free gFahrenheit = 78.6; RXS_ComposeVariable( fahrenheit : %Char(gFahrenheit) ); *INLR = *ON; /end-free ``` --- # RXS_Convert() > Performs common data conversions including Base64/Base64Url encoding and decoding, hex encoding, and CCSID character set conversion. RXS_Convert is a flexible subprocedure allowing you to perform many commonly required text and data conversions: - Convert to/from Base64 encoding - Perform XML entity encoding/decoding to replace characters with the appropriate XML entities: - `&` to `&` - `"` to `"` - `'` to `'` - `<` to `<` - `>` to `>` - Encode or decode a URL's querystring - Convert between CCSIDs (character sets) - Convert to uppercase or lowercase in a CCSID-aware manner - preferable to the common practice of using the %XLATE built-in function - General find & replace - you can specify your own characters/strings to perform replacements with. Essentially, this allows developers on IBM i OS 6.1 to access functionality similar to that of the %SCANRPL built-in function added in IBM i OS 7.1. ## Subprocedure Prototype ### IBM i 7.1+ ```rpgle // The output of the specified conversion operation is returned. D RXS_Convert... D PR Extproc('RXS_Convert') Opdesc D Like(RXS_Var16Mv_t) D Rtnparm // Field to hold the input of the selected conversion operation. You can // pass a field smaller than 16M without any additional effort. D Input Like(RXS_Var16Mv_t) Const D Options(*Varsize) // Holds settings which control how RXS_Convert operates. This parm can // accomodate a number of possible data structures, listed below. // Valid values: RXS_ConvertCcsidDS_t, RXS_ConvertCaseDS_t, // RXS_ConvertBase64DS_t, RXS_ConvertXMLEntitiesDS_t, // RXS_ConvertUrlPercentDS_t, RXS_ConvertUserDefinedDS_t D DS Like(RXS_Var64K_t) D Options(*Varsize) ``` ### IBM i 6.1 ```rpgle D RXS_Convert... D PR Extproc('RXS_Convert') Opdesc // Field to hold the output of the selected conversion operation. Note that // if you pass a field smaller than 16M, you will need to specify the // length of the Output in the subfield OutputLength. D Output Like(RXS_Var16Mv_t) D Options(*Varsize) // Field to hold the input of the selected conversion operation. You can // pass a field smaller than 16M without any additional effort. D Input Like(RXS_Var16Mv_t) Const D Options(*Varsize) // Holds settings which control how RXS_Convert operates. This parm can // accomodate a number of possible data structures, outlined below. // Valid values: RXS_ConvertCcsidDS_t, RXS_ConvertCaseDS_t, // RXS_ConvertBase64DS_t, RXS_ConvertXMLEntitiesDS_t, // RXS_ConvertUrlPercentDS_t, RXS_ConvertUserDefinedDS_t D DS Like(RXS_Var64K_t) D Options(*Varsize) ``` ## Example Code ### IBM i 7.1+ #### Base64 Encoding ```rpgle *-------------------------------------------------------------- * This example uses RXS_Convert() to encode data to Base64. * Base64 is commonly used to transfer binary data such as images * or cryptographic keys/hashes, but may be used on any data. * Important to note is that no CCSID conversion is performed on * the decoded data. If you are sending text, the receiver will * most likely not expect the data to be in EBCDIC, so you may * need to use RXS_Convert() to perform CCSID conversion prior * to performing Base64 encoding. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB D gRawData S Like(RXS_Var8Kv_t) D gBase64 S Like(RXS_Var8Kv_t) D gConvBase64DS DS LikeDS(RXS_ConvertBase64DS_t) /free gRawData = 'hello world!'; RXS_ResetDS( gConvBase64DS : RXS_DS_TYPE_CONVERTBASE64 ); gConvBase64DS.EncodeDecode = RXS_ENCODE; gBase64 = RXS_Convert( gRawData : gConvBase64DS ); // After encoding, gBase64 will contain: // aGVsbG8gd29ybGQh *INLR = *ON; /end-free ``` #### Base64 Decoding ```rpgle *-------------------------------------------------------------- * This example uses RXS_Convert() to decode Base64 encoded data. * Base64 is commonly used to transfer binary data such as images * or cryptographic keys/hashes, but may be used on any data. * Important to note is that no CCSID conversion is performed on * the decoded data. If you are receiving ASCII data that was * Base64 encoded, you may need to use RXS_Convert() to convert * it to a non-ASCII CCSID. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB D gBase64 S Like(RXS_Var8Kv_t) D gDecoded S Like(RXS_Var8Kv_t) D gConvBase64DS DS LikeDS(RXS_ConvertBase64DS_t) /free gBase64 = 'aGVsbG8gd29ybGQh'; RXS_ResetDS( gConvBase64DS : RXS_DS_TYPE_CONVERTBASE64 ); gConvBase64DS.EncodeDecode = RXS_DECODE; gDecoded = RXS_Convert( gBase64 : gConvBase64DS ); // After decoding, gDecoded will contain: // hello world! *INLR = *ON; /end-free ``` #### XML Entity Encoding ```rpgle *-------------------------------------------------------------- * This example uses RXS_Convert() to encode XML entites in * character data. Note that because < and > would need to be * encoded, you cannot use RXS_Convert() to encode a complete * XML document. Each item being composed into an XML element * would need to be individually encoded. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB D gData S Like(RXS_Var8Kv_t) D gEncoded S Like(RXS_Var8Kv_t) D gConvXMLEntDS DS LikeDS(RXS_ConvertXMLEntitiesDS_t) /free gData = 'Bob & Mary'; RXS_ResetDS( gConvXMLEntDS : RXS_DS_TYPE_CONVERTXMLENTITIES ); gConvXMLEntDS.EncodeDecode = RXS_ENCODE; gEncoded = RXS_Convert( gData : gConvXMLEntDS ); // After encoding, gEncoded will contain: // Bob & Mary *INLR = *ON; /end-free ``` #### XML Entity Decoding ```rpgle *-------------------------------------------------------------- * This example uses RXS_Convert() to decode XML entites back * to the corresponding character data. If you have an XML * document with encoded characters, it is generally safe to use * RXS_Convert() on the entire XML document. One exception to this * is when the XML document contains a nested complete XML document * which frequently occurs with .Net SOAP services. In that scenario, * you need to first parse the inner XML document out, and then * perform conversion. Failure to do this may result in an invalid * XML document. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB D gXML S Like(RXS_Var8Kv_t) D gDecoded S Like(RXS_Var8Kv_t) D gConvXMLEntDS DS LikeDS(RXS_ConvertXMLEntitiesDS_t) /free gXML = 'Bob & Mary'; RXS_ResetDS( gConvXMLEntDS : RXS_DS_TYPE_CONVERTXMLENTITIES ); gConvXMLEntDS.EncodeDecode = RXS_DECODE; gDecoded = RXS_Convert( gXML : gConvXMLEntDS ); // After decoding, gDecoded will contain: // Bob & Mary *INLR = *ON; /end-free ``` #### URL Percent Encoding ```rpgle *-------------------------------------------------------------- * This example uses RXS_Convert() to URL-encode data * (also known as 'percent encoding'). This is generally used * when passing values in a querystring within a URL. Note that * it is not possible to perform URL encoding on a complete URL * as many of the characters that make up a URL would be * erroneously converted. Instead, each value must be encoded * and concatenated to the URL. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB D gUrl S Like(RXS_Var1Kv_t) D gRawData S Like(RXS_Var8Kv_t) D gEncoded S Like(RXS_Var8Kv_t) D gConvUrlDS DS LikeDS(RXS_ConvertUrlPercentDS_t) /free gURL = 'http://www.example.com?key=' gRawData = 'hello world!'; RXS_ResetDS( gConvUrlDS : RXS_DS_TYPE_CONVERTURLPERCENT ); gConvUrlDS.EncodeDecode = RXS_ENCODE; gEncoded = RXS_Convert( gRawData : gConvUrlDS ); // After encoding, gEncoded will contain: // hello%20world%21 gURL += gEncoded; // gURL now contains: // http://www.example.com?key=hello%20world%21 *INLR = *ON; /end-free ``` #### URL Percent Decoding ```rpgle *-------------------------------------------------------------- * This example uses RXS_Convert() to decode URL-encoded data * (also known as 'percent encoded'). *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB D gEncoded S Like(RXS_Var8Kv_t) D gDecoded S Like(RXS_Var8Kv_t) D gConvUrlDS DS LikeDS(RXS_ConvertUrlPercentDS_t) /free gEncoded = 'key%3Dhello%20world%21'; RXS_ResetDS( gConvUrlDS : RXS_DS_TYPE_CONVERTURLPERCENT ); gConvUrlDS.EncodeDecode = RXS_DECODE; gDecoded = RXS_Convert( gEncoded : gConvUrlDS ); // After decoding, gDecoded will contain: // key=hello world! *INLR = *ON; /end-free ``` #### CCSID Conversion ```rpgle *-------------------------------------------------------------- * This example uses RXS_Convert() to perform CCSID conversion to * convert from ISO 8859-1 (CCSID 819) to EBCDIC (CCSID 37). *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB D gData819 S Like(RXS_Var8Kv_t) D gData37 S Like(RXS_Var8Kv_t) D gConvCcsidDS DS LikeDS(RXS_ConvertCcsidDS_t) /free gData819 = x'48656C6C6F20576F726C6421'; RXS_ResetDS( gConvCcsidDS : RXS_DS_TYPE_CONVERTCCSID ); gConvCcsidDS.From = RXS_CCSID_ISO88591; gConvCcsidDS.To = RXS_CCSID_EBCDIC; gData37 = RXS_Convert( gData819 : gConvCcsidDS ); // After conversion, gData37 will contain: // Hello World! *INLR = *ON; /end-free ``` #### Convert to Uppercase ```rpgle *-------------------------------------------------------------- * This example uses RXS_Convert() to convert lowercase characters * in gData to uppercase. This conversion happens in a CCSID * aware manner. For example, ü will be converted to Ü. This * is recommended over the common practice of using the %Xlate * function with A-Z/a-z constants. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB D gData S Like(RXS_Var8Kv_t) D gUppercase S Like(RXS_Var8Kv_t) D gConvCaseDS DS LikeDS(RXS_ConvertCaseDS_t) /free gData = 'Hello Günter'; RXS_ResetDS( gConvCaseDS : RXS_DS_TYPE_CONVERTCASE ); gConvCaseDS.UpperLower = RXS_UPPERCASE; gUppercase = RXS_Convert( gData : gConvCaseDS ); // After conversion, gLowercase will now contain // HELLO GÜNTER *INLR = *ON; /end-free ``` #### Convert to Lowercase ```rpgle *-------------------------------------------------------------- * This example uses RXS_Convert() to convert uppercase characters * in gData to lowercase. This conversion happens in a CCSID * aware manner. For example, Ü will be converted to ü. This * is recommended over the common practice of using the %Xlate * function with A-Z/a-z constants. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB D gData S Like(RXS_Var8Kv_t) D gLowercase S Like(RXS_Var8Kv_t) D gConvCaseDS DS LikeDS(RXS_ConvertCaseDS_t) /free gData = 'HELLO GÜNTER'; RXS_ResetDS( gConvCaseDS : RXS_DS_TYPE_CONVERTCASE ); gConvCaseDS.UpperLower = RXS_LOWERCASE; gLowercase = RXS_Convert( gData : gConvCaseDS ); // After conversion, gLowercase will now contain // hello günter *INLR = *ON; /end-free ``` #### User Defined Conversion (Scan & Replace) ```rpgle *-------------------------------------------------------------- * This example uses RXS_Convert() to replace instances of * specified characters or bytes with the provided replacements. * This was originally introduced to provide customers on IBM i * 6.1 with something similar to the %ScanRpl built-in function * which was only available on IBM i 7.1 or higher. Generally * if you are on IBM i 7.1 or higher, you can just use %ScanRpl. * The only advantage offered by using RXS_Convert() is that * up to 50 replacements may be specified, but each From and To * are limited to 32 bytes. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB D gInput S Like(RXS_Var8Kv_t) D gOutput S Like(RXS_Var8Kv_t) D gConvUsrDfnDS DS LikeDS(RXS_ConvertUserDefinedDS_t) /free gInput = 'This is a sample message'; RXS_ResetDS( gConvUsrDfnDS : RXS_DS_TYPE_CONVERTUSERDEFINED ); gConvUsrDfnDS.From(1) = 'sample'; gConvUsrDfnDS.To(1) = 'cool'; gConvUsrDfnDS.From(2) = 'message'; gConvUsrDfnDS.To(2) = 'message!'; gOutput = RXS_Convert( gInput : gConvUsrDfnDS ); // gOutput now contains: // This is a cool message! *INLR = *ON; /end-free ``` ### IBM i 6.1 #### Base64 Encoding ```rpgle *-------------------------------------------------------------- * This example uses RXS_Convert() to encode data to Base64. * Base64 is commonly used to transfer binary data such as images * or cryptographic keys/hashes, but may be used on any data. * Important to note is that no CCSID conversion is performed on * the decoded data. If you are sending text, the receiver will * most likely not expect the data to be in EBCDIC, so you may * need to use RXS_Convert() to perform CCSID conversion prior * to performing Base64 encoding. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /define RXSV6R1 /copy QRPGLECPY,RXSCB D gRawData S Like(RXS_Var8Kv_t) D gBase64 S Like(RXS_Var8Kv_t) D gConvBase64DS DS LikeDS(RXS_ConvertBase64DS_t) /free gRawData = 'hello world!'; RXS_ResetDS( gConvBase64DS : RXS_DS_TYPE_CONVERTBASE64 ); gConvBase64DS.EncodeDecode = RXS_ENCODE; RXS_Convert( gBase64 : gRawData : gConvBase64DS ); // After encoding, gBase64 will contain: // aGVsbG8gd29ybGQh *INLR = *ON; /end-free ``` #### Base64 Decoding ```rpgle *-------------------------------------------------------------- * This example uses RXS_Convert() to decode Base64 encoded data. * Base64 is commonly used to transfer binary data such as images * or cryptographic keys/hashes, but may be used on any data. * Important to note is that no CCSID conversion is performed on * the decoded data. If you are receiving ASCII data that was * Base64 encoded, you may need to use RXS_Convert() to convert * it to a non-ASCII CCSID. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /define RXSV6R1 /copy QRPGLECPY,RXSCB D gBase64 S Like(RXS_Var8Kv_t) D gDecoded S Like(RXS_Var8Kv_t) D gConvBase64DS DS LikeDS(RXS_ConvertBase64DS_t) /free gBase64 = 'aGVsbG8gd29ybGQh'; RXS_ResetDS( gConvBase64DS : RXS_DS_TYPE_CONVERTBASE64 ); gConvBase64DS.EncodeDecode = RXS_DECODE; RXS_Convert( gDecoded : gBase64 : gConvBase64DS ); // After decoding, gDecoded will contain: // hello world! *INLR = *ON; /end-free ``` #### XML Entity Encoding ```rpgle *-------------------------------------------------------------- * This example uses RXS_Convert() to encode XML entites in * character data. Note that because < and > would need to be * encoded, you cannot use RXS_Convert() to encode a complete * XML document. Each item being composed into an XML element * would need to be individually encoded. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /define RXSV6R1 /copy QRPGLECPY,RXSCB D gData S Like(RXS_Var8Kv_t) D gEncoded S Like(RXS_Var8Kv_t) D gConvXMLEntDS DS LikeDS(RXS_ConvertXMLEntitiesDS_t) /free gData = 'Bob & Mary'; RXS_ResetDS( gConvXMLEntDS : RXS_DS_TYPE_CONVERTXMLENTITIES ); gConvXMLEntDS.EncodeDecode = RXS_ENCODE; RXS_Convert( gEncoded : gData : gConvXMLEntDS ); // After encoding, gEncoded will contain: // Bob & Mary *INLR = *ON; /end-free ``` #### XML Entity Decoding ```rpgle *-------------------------------------------------------------- * This example uses RXS_Convert() to decode XML entites back * to the corresponding character data. If you have an XML * document with encoded characters, it is generally safe to use * RXS_Convert() on the entire XML document. One exception to this * is when the XML document contains a nested complete XML document * which frequently occurs with .Net SOAP services. In that scenario, * you need to first parse the inner XML document out, and then * perform conversion. Failure to do this may result in an invalid * XML document. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /define RXSV6R1 /copy QRPGLECPY,RXSCB D gXML S Like(RXS_Var8Kv_t) D gDecoded S Like(RXS_Var8Kv_t) D gConvXMLEntDS DS LikeDS(RXS_ConvertXMLEntitiesDS_t) /free gXML = 'Bob & Mary'; RXS_ResetDS( gConvXMLEntDS : RXS_DS_TYPE_CONVERTXMLENTITIES ); gConvXMLEntDS.EncodeDecode = RXS_DECODE; RXS_Convert( gDecoded : gXML : gConvXMLEntDS ); // After decoding, gDecoded will contain: // Bob & Mary *INLR = *ON; /end-free ``` #### URL Percent Encoding ```rpgle *-------------------------------------------------------------- * This example uses RXS_Convert() to URL-encode data * (also known as 'percent encoding'). This is generally used * when passing values in a querystring within a URL. Note that * it is not possible to perform URL encoding on a complete URL * as many of the characters that make up a URL would be * erroneously converted. Instead, each value must be encoded * and concatenated to the URL. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /define RXSV6R1 /copy QRPGLECPY,RXSCB D gUrl S Like(RXS_Var1Kv_t) D gRawData S Like(RXS_Var8Kv_t) D gEncoded S Like(RXS_Var8Kv_t) D gConvUrlDS DS LikeDS(RXS_ConvertUrlPercentDS_t) /free gURL = 'http://www.example.com?key=' gRawData = 'hello world!'; RXS_ResetDS( gConvUrlDS : RXS_DS_TYPE_CONVERTURLPERCENT ); gConvUrlDS.EncodeDecode = RXS_ENCODE; RXS_Convert( gEncoded : gRawData : gConvUrlDS ); // After encoding, gEncoded will contain: // hello%20world%21 gURL += gEncoded; // gURL now contains: // http://www.example.com?key=hello%20world%21 *INLR = *ON; /end-free ``` #### URL Percent Decoding ```rpgle *-------------------------------------------------------------- * This example uses RXS_Convert() to decode URL-encoded data * (also known as 'percent encoded'). *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /define RXSV6R1 /copy QRPGLECPY,RXSCB D gEncoded S Like(RXS_Var8Kv_t) D gDecoded S Like(RXS_Var8Kv_t) D gConvUrlDS DS LikeDS(RXS_ConvertUrlPercentDS_t) /free gEncoded = 'key%3Dhello%20world%21'; RXS_ResetDS( gConvUrlDS : RXS_DS_TYPE_CONVERTURLPERCENT ); gConvUrlDS.EncodeDecode = RXS_DECODE; RXS_Convert( gDecoded : gEncoded : gConvUrlDS ); // After decoding, gDecoded will contain: // key=hello world! *INLR = *ON; /end-free ``` #### CCSID Conversion ```rpgle *-------------------------------------------------------------- * This example uses RXS_Convert() to perform CCSID conversion to * convert from ISO 8859-1 (CCSID 819) to EBCDIC (CCSID 37). *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /define RXSV6R1 /copy QRPGLECPY,RXSCB D gData819 S Like(RXS_Var8Kv_t) D gData37 S Like(RXS_Var8Kv_t) D gConvCcsidDS DS LikeDS(RXS_ConvertCcsidDS_t) /free gData819 = x'48656C6C6F20576F726C6421'; RXS_ResetDS( gConvCcsidDS : RXS_DS_TYPE_CONVERTCCSID ); gConvCcsidDS.From = RXS_CCSID_ISO88591; gConvCcsidDS.To = RXS_CCSID_EBCDIC; RXS_Convert( gData37 : gData819 : gConvCcsidDS ); // After conversion, gData37 will contain: // Hello World! *INLR = *ON; /end-free ``` #### Convert to Uppercase ```rpgle *-------------------------------------------------------------- * This example uses RXS_Convert() to convert lowercase characters * in gData to uppercase. This conversion happens in a CCSID * aware manner. For example, ü will be converted to Ü. This * is recommended over the common practice of using the %Xlate * function with A-Z/a-z constants. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /define RXSV6R1 /copy QRPGLECPY,RXSCB D gData S Like(RXS_Var8Kv_t) D gUppercase S Like(RXS_Var8Kv_t) D gConvCaseDS DS LikeDS(RXS_ConvertCaseDS_t) /free gData = 'Hello Günter'; RXS_ResetDS( gConvCaseDS : RXS_DS_TYPE_CONVERTCASE ); gConvCaseDS.UpperLower = RXS_UPPERCASE; RXS_Convert( gUppercase : gData : gConvCaseDS ); // After conversion, gUppercase will now contain // HELLO GÜNTER *INLR = *ON; /end-free ``` #### Convert to Lowercase ```rpgle *-------------------------------------------------------------- * This example uses RXS_Convert() to convert uppercase characters * in gData to lowercase. This conversion happens in a CCSID * aware manner. For example, Ü will be converted to ü. This * is recommended over the common practice of using the %Xlate * function with A-Z/a-z constants. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /define RXSV6R1 /copy QRPGLECPY,RXSCB D gData S Like(RXS_Var8Kv_t) D gLowercase S Like(RXS_Var8Kv_t) D gConvCaseDS DS LikeDS(RXS_ConvertCaseDS_t) /free gData = 'HELLO GÜNTER'; RXS_ResetDS( gConvCaseDS : RXS_DS_TYPE_CONVERTCASE ); gConvCaseDS.UpperLower = RXS_LOWERCASE; RXS_Convert( gLowercase : gData : gConvCaseDS ); // After conversion, gLowercase will now contain // hello günter *INLR = *ON; /end-free ``` #### User Defined Conversion (Scan & Replace) ```rpgle *-------------------------------------------------------------- * This example uses RXS_Convert() to replace instances of * specified characters or bytes with the provided replacements. * This was originally introduced to provide customers on IBM i * 6.1 with something similar to the %ScanRpl built-in function * which was only available on IBM i 7.1 or higher. Generally * if you are on IBM i 7.1 or higher, you can just use %ScanRpl. * The only advantage offered by using RXS_Convert() is that * up to 50 replacements may be specified, but each From and To * are limited to 32 bytes. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /define RXSV6R1 /copy QRPGLECPY,RXSCB D gInput S Like(RXS_Var8Kv_t) D gOutput S Like(RXS_Var8Kv_t) D gConvUsrDfnDS DS LikeDS(RXS_ConvertUserDefinedDS_t) /free gInput = 'This is a sample message'; RXS_ResetDS( gConvUsrDfnDS : RXS_DS_TYPE_CONVERTUSERDEFINED ); gConvUsrDfnDS.From(1) = 'sample'; gConvUsrDfnDS.To(1) = 'cool'; gConvUsrDfnDS.From(2) = 'message'; gConvUsrDfnDS.To(2) = 'message!'; RXS_Convert( gOutput : gInput : gConvUsrDfnDS ); // gOutput now contains: // This is a cool message! *INLR = *ON; /end-free ``` ## Data Structures ### RXS_ConvertBase64DS_t ```rpgle D RXS_ConvertBase64DS_t... D DS Qualified Template Inz D ReturnedErrorInfo... D LikeDS(RXS_ReturnedErrorInfoDS_t) Inz D DataStructureType... D 5I 0 Inz(RXS_DS_TYPE_CONVERTBASE64) D OnErrorMessageType... D 5I 0 // Set to RXS_ENCODE or RXS_DECODE. // Valid values: RXS_ENCODE, RXS_DECODE // Default: RXS_DECODE D EncodeDecode N // Internal use only D InputPointer... D * // Internal use only D InputLength 10I 0 // Internal use only D OutputPointer... D * // Internal use only D OutputLength 10I 0 // Internal use only D Reserved 2048A ``` ### RXS_ConvertXmlEntitiesDS_t ```rpgle D RXS_ConvertXMLEntitiesDS_t... D DS Qualified Template Inz D ReturnedErrorInfo... D LikeDS(RXS_ReturnedErrorInfoDS_t) Inz D DataStructureType... D 5I 0 Inz(RXS_DS_TYPE_CONVERTXMLENTITIES) D OnErrorMessageType... D 5I 0 // Set to RXS_ENCODE or RXS_DECODE. // Valid values: RXS_ENCODE, RXS_DECODE // Default: RXS_DECODE D EncodeDecode N // Internal use only D InputPointer... D * // Internal use only D InputLength 10I 0 // Internal use only D OutputPointer... D * // Internal use only D OutputLength 10I 0 // Internal use only D Reserved 2049A ``` ### RXS_ConvertUrlPercentDS_t ```rpgle D RXS_ConvertUrlPercentDS_t... D DS Qualified Template Inz D ReturnedErrorInfo... D LikeDS(RXS_ReturnedErrorInfoDS_t) Inz D DataStructureType... D 5I 0 Inz(RXS_DS_TYPE_CONVERTURLPERCENT) D OnErrorMessageType... D 5I 0 // Set to RXS_ENCODE or RXS_DECODE. // Valid values: RXS_ENCODE, RXS_DECODE // Default: RXS_DECODE D EncodeDecode N // Determines whether the returned encoded hexadecimal values are returned // as ASCII bytes (RXS_ASCII) or converted to EBCDIC (RXS_EBCDIC). // Valid values: RXS_ASCII, RXS_EBCDIC // Default: RXS_ASCII D AsciiEbcdic N // Internal use only D InputPointer... D * // Internal use only D InputLength 10I 0 // Internal use only D OutputPointer... D * // Internal use only D OutputLength 10I 0 // Internal use only D Reserved 2050A ``` ### RXS_ConvertCcsidDS_t ```rpgle D RXS_ConvertCcsidDS_t... D DS Qualified Template Inz D ReturnedErrorInfo... D LikeDS(RXS_ReturnedErrorInfoDS_t) Inz D DataStructureType... D 5I 0 Inz(RXS_DS_TYPE_CONVERTCCSID) D OnErrorMessageType... D 5I 0 // CCSID to convert the input data from. D From 10I 0 // CCSID to convert the input data to. D To 10I 0 // Internal use only D InputPointer... D * // Internal use only D InputLength 10I 0 // Internal use only D OutputPointer... D * // Internal use only D OutputLength 10I 0 // Internal use only D Reserved 2048A ``` ### RXS_ConvertCaseDS_t ```rpgle D RXS_ConvertCaseDS_t... D DS Qualified Template Inz D ReturnedErrorInfo... D LikeDS(RXS_ReturnedErrorInfoDS_t) Inz D DataStructureType... D 5I 0 Inz(RXS_DS_TYPE_CONVERTCASE) D OnErrorMessageType... D 5I 0 // The CCSID of the input string. Defaults to the CCSID of the current job. D Ccsid 10I 0 // Set to RXS_UPPERCASE or RXS_LOWERCASE. // Valid values: RXS_UPPERCASE, RXS_LOWERCASE // Default: RXS_UPPERCASE D UpperLower N // Internal use only D InputPointer... D * // Internal use only D InputLength 10I 0 // Internal use only D OutputPointer... D * // Internal use only D OutputLength 10I 0 // Internal use only D Reserved 2050A ``` ### RXS_ConvertUserDefinedDS_t ```rpgle D RXS_ConvertUserDefinedDS_t... D DS Qualified Template Inz D ReturnedErrorInfo... D LikeDS(RXS_ReturnedErrorInfoDS_t) Inz D DataStructureType... D 5I 0 Inz(RXS_DS_TYPE_CONVERTUSERDEFINED) D OnErrorMessageType... D 5I 0 D From 32A Varying Dim(50) D To 32A Varying Dim(50) // Internal use only D InputPointer... D * // Internal use only D InputLength 10I 0 // Internal use only D OutputPointer... D * // Internal use only D OutputLength 10I 0 // Internal use only D Reserved 2048A ``` --- # RXS_Crypt() > Encrypts or decrypts data using symmetric algorithms with configurable key, IV, and padding options. This subprocedure performs cryptographic operations like hashing and encryption. Currently supported operations are: - MD5 - SHA1 - SHA256 - SHA384 - SHA512 ## Subprocedure Prototype ### IBM i 7.1+ ```rpgle // Returns the output of the specified hashing/crytographic operation is // returned. D RXS_Crypt... D PR Extproc('RXS_Crypt') Opdesc D Like(RXS_Var16Mv_t) D Rtnparm // Field to hold the input of the selected hashing/crytographic operation. // You can pass a field smaller than 16M without any additional effort. D Input Like(RXS_Var16Mv_t) Const D Options(*Varsize) // Holds settings which control how RXS_Crypt operates. This parm can // accomodate a number of possible data structures, listed below. D DS Like(RXS_Var64K_t) D Options(*Varsize) ``` ### IBM i 6.1 ```rpgle D RXS_Crypt... D PR Extproc('RXS_Crypt') Opdesc // Field to hold the output of the selected hashing/crytographic operation. // Note that if you pass a field smaller than 16M, you will need to specify // the length of the Output in the subfield OutputLength. D Output Like(RXS_Var16Mv_t) D Options(*Varsize) // Field to hold the input of the selected hashing/crytographic operation. // You can pass a field smaller than 16M without any additional effort. D Input Like(RXS_Var16Mv_t) Const D Options(*Varsize) // Holds settings which control how RXS_Crypt operates. This parm can // accomodate a number of possible data structures, listed below. D DS Like(RXS_Var64K_t) D Options(*Varsize) ``` ## Example Code ### IBM i 7.1+ #### Example 1: MD5 Hash of Character Field ```rpgle *-------------------------------------------------------------- * This example code calculates an MD5 hash from a character field. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB D HashMD5DS DS LikeDS(RXS_MD5CryptDS_t) D Data S Like(RXS_Var1Kv_t) D Hash S Like(RXS_Var1Kv_t) /free Data = 'Hello World'; RXS_ResetDS( HashMD5DS : RXS_DS_TYPE_MD5CRYPT ); Hash = RXS_Crypt( Data : HashMD5DS ); RXS_JobLog( 'Hash: %s' : Hash ); // Output: Hash: B10A8DB164E0754105B7A99BE72E3FE5 *INLR = *ON; /end-free ``` ### IBM i 6.1 #### Example 1: MD5 Hash of Character Field ```rpgle *-------------------------------------------------------------- * This example code calculates an MD5 hash from a character field. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /define RXSV6R1 /copy QRPGLECPY,RXSCB D HashMD5DS DS LikeDS(RXS_MD5CryptDS_t) D Data S Like(RXS_Var1Kv_t) D Hash S Like(RXS_Var1Kv_t) /free Data = 'Hello World'; RXS_ResetDS( HashMD5DS : RXS_DS_TYPE_MD5CRYPT ); RXS_Crypt( Hash : Data : HashMD5DS ); RXS_JobLog( 'Hash: %s' : Hash ); // Output: Hash: B10A8DB164E0754105B7A99BE72E3FE5 *INLR = *ON; /end-free ``` ## Data Structures ### RXS_MD5CryptDS_t ```rpgle D RXS_MD5CryptDS_t... D DS Qualified Template Inz D ReturnedErrorInfo... D LikeDS(RXS_ReturnedErrorInfoDS_t) Inz D OnErrorMessageType... D 10I 0 // Optional IFS stream file to use as input data for hash operation. D InputStmf Like(RXS_Var1Kv_t) // CCSID of input data. Used when the input data is of a different CCSID of // the job CCSID. Not necessary if using InputStmf. D InputCcsid 10I 0 Inz(RXS_CCSID_JOB) // CCSID to convert the input data into before hashing. Note that this is // typically going to be RXS_CCSID_ISO88591 or RXS_CCSID_UTF8. D EncryptAsCcsid... D 10I 0 Inz(RXS_CCSID_ISO88591) // Internal use only D InputPointer... D * // Internal use only D InputLength 10I 0 // Internal use only D OutputPointer... D * // Internal use only D OutputLength 10I 0 // Internal use only D Reserved 2048A ``` ### RXS_SHACryptDS_t ```rpgle D RXS_SHACryptDS_t... D DS Qualified Template Inz D ReturnedErrorInfo... D LikeDS(RXS_ReturnedErrorInfoDS_t) Inz D OnErrorMessageType... D 10I 0 // Determines which SHA algorithm/block size to use when hashing. // Valid values: RXS_CRYPT_SHA1_ALGORITHM, RXS_CRYPT_SHA256_ALGORITHM, // RXS_CRYPT_SHA384_ALGORITHM, RXS_CRYPT_SHA512_ALGORITHM D Algorithm 4P 3 // Optional IFS stream file to use as input data for hash operation. D InputStmf Like(RXS_Var1Kv_t) // CCSID of input data. Used when the input data is of a different CCSID of // the job CCSID. Not necessary if using InputStmf. D InputCcsid 10I 0 Inz(RXS_CCSID_JOB) // CCSID to convert the input data into before hashing. Note that this is // typically going to be RXS_CCSID_ISO88591 or RXS_CCSID_UTF8. D EncryptAsCcsid... D 10I 0 Inz(RXS_CCSID_ISO88591) // Internal use only D InputPointer... D * // Internal use only D InputLength 10I 0 // Internal use only D OutputPointer... D * // Internal use only D OutputLength 10I 0 // Internal use only D Reserved 2049A ``` --- # RXS_GetComposeBuffer() > Returns the current contents of the compose engine output buffer as a character string. Retrieves the current composition engine buffer into a variable. The buffer is cleared upon successful retreival. ## Subprocedure Prototype ### IBM i 7.1+ ```rpgle // Returns the current contents of the compose engine buffer. D RXS_GetComposeBuffer... D PR Extproc('RXS_GetComposeBuffer') D Opdesc Like(RXS_Var16Mv_t) D Rtnparm ``` ### IBM i 6.1 ```rpgle D RXS_GetComposeBuffer... D PR Extproc('RXS_GetComposeBuffer') D Opdesc // Holds the current contents of the compose engine buffer. D Buffer Like(RXS_Var16Mv_t) Options(*Varsize) ``` ## Example Code ### IBM i 7.1+ #### Example 1 ```rpgle *-------------------------------------------------------------- * This example code retrieves the composition engine buffer and stores it in the field gXmlRequest. * This process might be used when calling a web service. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB D gXmlRequest S Like(RXS_Var64Kv_t) /free gXmlRequest = RXS_GetComposeBuffer(); *INLR = *ON; /end-free ``` ### IBM i 6.1 #### Example 1 ```rpgle *-------------------------------------------------------------- * This example code retrieves the composition engine buffer and stores it in the field gXmlRequest. * This process might be used when calling a web service. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /define RXSV6R1 /copy QRPGLECPY,RXSCB D gXmlRequest S Like(RXS_Var64Kv_t) /free RXS_GetComposeBuffer( gXmlRequest ); *INLR = *ON; /end-free ``` --- # RXS_GetEnvVar() > Retrieves Apache environment variables and HTTP request headers for use in hosted web service programs. This subprocedure is used to retrieve Apache server's environment variables as well as some incoming HTTP headers. This is typically used in a scenario when you are hosting a web service. - AUTH_TYPE - CGI_ASCII_CCSID - CGI_EBCDIC_CCSID - CONTENT_LENGTH - CONTENT_TYPE - GATEWAY_INTERFACE - HTTP_ACCEPT - HTTP_USER_AGENT - PATH_INFO - PATH_TRANSLATED - QUERY_STRING - REMOTE_ADDR - REMOTE_HOST - REMOTE_IDENT - REQUEST_METHOD - REMOTE_USER - SCRIPT_NAME - SERVER_NAME - SERVER_PORT - SERVER_PROTOCOL - SERVER_SOFTWARE This subprocedure can also be used to retrieve environment variables set with [RXS_PutEnvVar()](https://isupport.katointegrations.com/rxs/3.2/rxs_putenvvar.md). ## Subprocedure Prototype ### IBM i 7.1+ ```rpgle // Returns the data retrieved from the environment variable. D RXS_GetEnvVar... D PR Extproc('RXS_GetEnvVar') Opdesc D Like(RXS_Var16Mv_t) D Rtnparm // Specify the name of the environment variable to retrieve the value of. D EnvVar 30A Value ``` ### IBM i 6.1 ```rpgle D RXS_GetEnvVar... D PR Extproc('RXS_GetEnvVar') Opdesc // Holds the data retrieved from the environment variable. D Output Like(RXS_Var16Mv_t) D Options(*varsize) // Specify the name of the environment variable to retrieve the value of. D EnvVar 30A Value ``` ## Example Code ### IBM i 7.1+ #### Example 1: Retrieving an Environment Variable ```rpgle *-------------------------------------------------------------- * This example code retrieves an environment variable. * The environment variable being retrieved, REQUEST_METHOD, would * be set by the Apache server, which means that it can only be * retrieved if this program is used as a web service. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB D Data S Like(RXS_Var1Kv_t) /free Data = RXS_GetEnvVar( 'REQUEST_METHOD' ); RXS_JobLog( 'REQUEST METHOD? %s' : Data ); *INLR = *ON; /end-free ``` ### IBM i 6.1 #### Example 1: Retrieving an Environment Variable ```rpgle *-------------------------------------------------------------- * This example code retrieves an environment variable. * The environment variable being retrieved, REQUEST_METHOD, would * be set by the Apache server, which means that it can only be * retrieved if this program is used as a web service. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /define RXSV6R1 /copy QRPGLECPY,RXSCB D Data S Like(RXS_Var1Kv_t) /free RXS_GetEnvVar( Data : 'REQUEST_METHOD' ); RXS_JobLog( 'REQUEST METHOD? %s' : Data ); *INLR = *ON; /end-free ``` --- # RXS_GetJobCcsid() > Returns the CCSID of the current job. This subprocedure retrieves the CCSID of the current job. This may be used in character data conversion, such as with [RXS_Convert()](https://isupport.katointegrations.com/rxs/3.2/rxs_convert.md). ## Subprocedure Prototype ### IBM i 6.1+ ```rpgle // Returns the CCSID of the current job. D RXS_GetJobCcsid... D PR 10I 0 Extproc('RXS_GetJobCcsid') Opdesc ``` ## Example Code ### IBM i 6.1+ #### Example 1: Job CCSID Retrieval ```rpgle *-------------------------------------------------------------- * This example code retrieves the CCSID, and then outputs it to * the job log using RXS_JobLog(); *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB D CCSID S 10I 0 /free CCSID = RXS_GetJobCCSID(); RXS_JobLog( 'Job CCSID: %s' : %Char(CCSID) ); *INLR = *ON; /end-free ``` --- # RXS_GetStdIn() > Reads the HTTP request body (stdin) into an RPG variable; used to receive POST data in hosted web service programs. This subprocedure is used to read data sent to you via HTTP POST into a field up to 16MB, or into an IFS STMF file. This is typically used when you are offering a web service. ## Subprocedure Prototype ### IBM i 7.1+ ```rpgle // Returns the data retrieved from STDIN. D RXS_GetStdIn... D PR Extproc('RXS_GetStdIn') Opdesc D Like(RXS_Var16Mv_t) D Rtnparm // Optional RXS_GetStdInDS_t data structure used to convert received data // to a specified CCSID. D DS Likeds(RXS_GetStdInDS_t) D Options(*Varsize:*Nopass) ``` ### IBM i 6.1 ```rpgle D RXS_GetStdIn... D PR Extproc('RXS_GetStdIn') Opdesc // Holds the data retrieved from STDIN. D Output Like(RXS_Var16Mv_t) D Options(*Varsize) // Optional RXS_GetStdInDS_t data structure used to convert received data // to a specified CCSID. D DS Likeds(RXS_GetStdInDS_t) D Options(*Varsize:*Nopass) ``` ## Example Code ### IBM i 7.1+ #### Example 1 ```rpgle *-------------------------------------------------------------- * This example code retrieves data from standard in and stores it * in the field gXmlRequest. * This process might be used when offering a web service. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB D gXmlRequest S Like(RXS_Var64Kv_t) /free gXmlRequest = RXS_GetStdIn(); *INLR = *ON; /end-free ``` ### IBM i 6.1 #### Example 1 ```rpgle *-------------------------------------------------------------- * This example code retrieves data from STDIN and write it * to the specified IFS file. * This process might be used when offering a web service. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /define RXSV6R1 /copy QRPGLECPY,RXSCB D GetStdInDS DS LikeDS(RXS_GetStdInDS_t) /free RXS_ResetDS( GetStdInDS : RXS_DS_TYPE_GETSTDIN ); GetStdInDS.Stmf = '/tmp/over16mb.xml'; RXS_GetStdIn(GetStdInDS); *INLR = *ON; /end-free ``` ## Data Structures ### RXS_GetStdInDS_t ```rpgle D RXS_GetStdInDS_t... D DS Qualified Template Inz D ReturnedErrorInfo... D LikeDS(RXS_ReturnedErrorInfoDS_t) Inz D DataStructureType... D 5I 0 Inz(RXS_DS_TYPE_GETSTDIN) D OnErrorMessageType... D 5I 0 // Specifies the CCSID to convert the inbound data into. D Ccsid 10I 0 // Specifies the STMF to load with the contents of STDIN. D Stmf Like(RXS_Var1Kv_t) ``` --- # RXS_GetStmf() > Reads the contents of an IFS stream file into an RPG variable. This subprocedure retrieves up to 16MB of data from a specified IFS stream file. ## Subprocedure Prototype ### IBM i 7.1+ ```rpgle // Returns data retrieved from the specified IFS stream file. D RXS_GetStmf... D PR Extproc('RXS_GetStmf') Opdesc D Like(RXS_Var16Mv_t) D Rtnparm // RXS_GetStmfDS_t data structure used to configure the RXS_GetStmf() call // and specify the IFS stream file to read. D DS Likeds(RXS_GetStmfDS_t) ``` ### IBM i 6.1 ```rpgle D RXS_GetStmf... D PR Extproc('RXS_GetStmf') // Holds the data retrieved from the specified IFS stream file. D Output Like(RXS_Var16Mv_t) D Options(*Varsize) // RXS_GetStmfDS_t data structure used to configure the RXS_GetStmf() call // and specify the IFS stream file to read. D DS Likeds(RXS_GetStmfDS_t) D Options(*Varsize) ``` ## Example Code ### IBM i 7.1+ #### Example 1: Read Character String from IFS stream file ```rpgle *-------------------------------------------------------------- * This example code reads the contents of the file * /tmp/rxs_getstmf.txt into the Data field. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB D GetStmfDS DS LikeDS(RXS_GetStmfDS_t) D Data S Like(RXS_Var64Kv_t) /free RXS_ResetDS( GetStmfDS : RXS_DS_TYPE_GETSTMF ); GetStmfDS.Stmf = '/tmp/rxs_getstmf.txt'; Data = RXS_GetStmf( GetStmfDS ); *INLR = *ON; /end-free ``` #### Example 2: Read Chunks of Characters from an IFS stream file while looping ```rpgle *-------------------------------------------------------------- * This example code reads the contents of the file * /tmp/rxs_getstmf.txt and outputs the entire file to STDOUT, * even if the length of the file is greater than the Data variable. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB D GetStmfDS DS LikeDS(RXS_GetStmfDS_t) D Data S Like(RXS_Var64Kv_t) /free RXS_ResetDS( GetStmfDS : RXS_DS_TYPE_GETSTMF ); GetStmfDS.Stmf = '/tmp/rxs_getstmf.txt'; GetStmfDS.ChunkedLength = %size(Data - 4); Dou %len(Data) = 0; Data = RXS_GetStmf( GetStmfDS ); RXS_PutStdOut( Data ); Enddo; *INLR = *ON; /end-free ``` ### IBM i 6.1 #### Example 1: Read Character String from IFS stream file ```rpgle *-------------------------------------------------------------- * This example code reads the contents of the file * /tmp/rxs_getstmf.txt into the Data field. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /define RXSV6R1 /copy QRPGLECPY,RXSCB D GetStmfDS DS LikeDS(RXS_GetStmfDS_t) D Data S Like(RXS_Var64Kv_t) /free RXS_ResetDS( GetStmfDS : RXS_DS_TYPE_GETSTMF ); GetStmfDS.Stmf = '/tmp/rxs_getstmf.txt'; RXS_GetStmf( Data : GetStmfDS ); *INLR = *ON; /end-free ``` #### Example 2: Read Chunks of Characters from an IFS stream file while looping ```rpgle *-------------------------------------------------------------- * This example code reads the contents of the file * /tmp/rxs_getstmf.txt and outputs the entire file to STDOUT, * even if the length of the file is greater than the Data variable. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /define RXSV6R1 /copy QRPGLECPY,RXSCB D GetStmfDS DS LikeDS(RXS_GetStmfDS_t) D Data S Like(RXS_Var64Kv_t) /free RXS_ResetDS( GetStmfDS : RXS_DS_TYPE_GETSTMF ); GetStmfDS.Stmf = '/tmp/rxs_getstmf.txt'; GetStmfDS.ChunkedLength = %size(Data - 4); Dou %len(Data) = 0; RXS_GetStmf( Data : GetStmfDS ); RXS_PutStdOut( Data ); Enddo; *INLR = *ON; /end-free ``` ## Data Structures ### RXS_GetStmfDS_t ```rpgle D RXS_GetStmfDS_t... D DS Qualified Template Inz D ReturnedErrorInfo... D LikeDS(RXS_ReturnedErrorInfoDS_t) Inz // Internal use only D DataStructureType... D 5I 0 Inz(RXS_DS_TYPE_GETSTMF) D OnErrorMessageType... D 5I 0 // Specifies IFS path to a stream file to retrieve. D Stmf Like(RXS_Var1Kv_t) // The CCSID to convert the data read from the IFS stream file into. D ToCcsid 10I 0 // Internal use only D OutputPointer... D * Inz(*Null) // Internal use only D OutputLength 10I 0 // This is a returned value containing the number of bytes stored in the // stream file. D StmfSize 10I 0 // The length to use when "chunks" of the stream file are to be returned. // See example 2. D ChunkedLength... D 10I 0 // Internal use only D ChunkedOffset... D 128A ``` --- # RXS_GetUrlVar() > Extracts a named variable from the URL query string; used to read GET parameters in hosted web service programs. This subprocedure is used to retrieve variables from the URL that was used to call the current program as a web service. Variables on a URL are specified in name-value pairs. For example: `http://mysite.com/rxs/mywebservice?customer=1&code=3` In this example, there are two variables: **customer** and **code**, and each of them has a value of 1 and 3 respectively. **Note:** This API is only meant to be used in a program acting as a webservice. Using it in other programs will throw errors. ## Subprocedure Prototype ### IBM i 7.1+ ```rpgle // Returns the data retrieved from the URL variable. D RXS_GetUrlVar... D PR Extproc('RXS_GetUrlVar') Opdesc D Like(RXS_Var16Mv_t) D Rtnparm // Specify the name of the URL variable which is to be retrieved. D UrlVar 300A Value D Input Like(RXS_Var16Mv_t) D Options(*Nopass:*Varsize) ``` ### IBM i 6.1 ```rpgle D RXS_GetUrlVar... D PR Extproc('RXS_GetUrlVar') Opdesc // Holds the data retrieved from the URL variable. D Output Like(RXS_Var16Mv_t) D Options(*Varsize) // Specify the name of the URL variable to retrieve the value of. D UrlVar 300A Value D Input Like(RXS_Var16Mv_t) D Options(*Nopass:*Varsize) ``` ## Example Code ### IBM i 7.1+ #### Example 1: Retrieve Values from the Querystring of a URL ```rpgle *-------------------------------------------------------------- * This example code retrieves variable values from the URL that * was used to call this program. * For example, if this program were called with the following URL: * http://mysite.com/rxs/mywebservice?customer=1&code=3 * The output in the job log would be: * Customer: 1 * Code: 3 *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /define RXSV6R1 /copy QRPGLECPY,RXSCB D VarCustomer S Like(RXS_Var1Kv_t) D VarCode S Like(RXS_Var1Kv_t) /free VarCustomer = RXS_GetUrlVar( 'customer' ); VarCode = RXS_GetUrlVar( 'code' ); RXS_JobLog( 'Customer: %s' : VarCustomer ); RXS_JobLog( 'Code: %s' : VarCode ); *INLR = *ON; /end-free ``` #### Example 2: Retrieve Values from the Path of a URL ```rpgle *-------------------------------------------------------------- * This example code retrieves variable values from the URL that * was used to call this program. * For example, if this program were called with the following URL: * http://mysite.com/rxs/mywebservice/customer/15/code/43 * The output in the job log would be: * Customer: 5 * Code: 43 *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /define RXSV6R1 /copy QRPGLECPY,RXSCB D VarCustomer S Like(RXS_Var1Kv_t) D VarCode S Like(RXS_Var1Kv_t) /free VarCustomer = RXS_GetUrlVar( 'customer/' ); VarCode = RXS_GetUrlVar( 'code/' ); RXS_JobLog( 'Customer: %s' : VarCustomer ); RXS_JobLog( 'Code: %s' : VarCode ); *INLR = *ON; /end-free ``` ### IBM i 6.1 #### Example 1: Retrieve Values from the Querystring of a URL ```rpgle *-------------------------------------------------------------- * This example code retrieves variable values from the URL that * was used to call this program. * For example, if this program were called with the following URL: * http://mysite.com/rxs/mywebservice?customer=1&code=3 * The output in the job log would be: * Customer: 1 * Code: 3 *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /define RXSV6R1 /copy QRPGLECPY,RXSCB D VarCustomer S Like(RXS_Var1Kv_t) D VarCode S Like(RXS_Var1Kv_t) /free RXS_GetUrlVar( VarCustomer : 'customer' ); RXS_GetUrlVar( VarCode : 'code' ); RXS_JobLog( 'Customer: %s' : VarCustomer ); RXS_JobLog( 'Code: %s' : VarCode ); *INLR = *ON; /end-free ``` #### Example 2: Retrieve Values from the Path of a URL ```rpgle *-------------------------------------------------------------- * This example code retrieves variable values from the URL that * was used to call this program. * For example, if this program were called with the following URL: * http://mysite.com/rxs/mywebservice/customer/15/code/43 * The output in the job log would be: * Customer: 5 * Code: 43 *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /define RXSV6R1 /copy QRPGLECPY,RXSCB D VarCustomer S Like(RXS_Var1Kv_t) D VarCode S Like(RXS_Var1Kv_t) /free RXS_GetUrlVar( VarCustomer : 'customer/' ); RXS_GetUrlVar( VarCode : 'code/' ); RXS_JobLog( 'Customer: %s' : VarCustomer ); RXS_JobLog( 'Code: %s' : VarCode ); *INLR = *ON; /end-free ``` --- # RXS_JobLog() > Writes a message to the job log. This subprocedure is used to easily output messages to the job log. A single character field can be passed in to output in a direct and unmodified fashion, or the API can be called with multiple character data parameters and utilize character replacement. To perform character replacement, you'll need to include one or more placeholders, indicated by the following string: `%s` Each Replacement# parameter will replace the corresponding `%s`. For example, Replacement1 will replace the first `%s`, while Replacement6 will replace the sixth `%s` present in the string. ## Subprocedure Prototype ### IBM i 6.1+ ```rpgle D RXS_JobLog... D PR Extproc('RXS_JobLog') D Opdesc // Simple character data message to be printed to the job log, or a // formatted character data string to use with replacements. D Output Like(RXS_Var32Kv_t) Const D Options(*Varsize) // Optional: Used as a replacement in the formatted character data string // passed in Output. D Replacement1... D Like(RXS_Var1Kv_t) Const D Options(*Varsize: *Nopass) // Optional: Used as a replacement in the formatted character data string // passed in Output. D Replacement2... D Like(RXS_Var1Kv_t) Const D Options(*Varsize: *Nopass) // Optional: Used as a replacement in the formatted character data string // passed in Output. D Replacement3... D Like(RXS_Var1Kv_t) Const D Options(*Varsize: *Nopass) // Optional: Used as a replacement in the formatted character data string // passed in Output. D Replacement4... D Like(RXS_Var1Kv_t) Const D Options(*Varsize: *Nopass) // Optional: Used as a replacement in the formatted character data string // passed in Output. D Replacement5... D Like(RXS_Var1Kv_t) Const D Options(*Varsize: *Nopass) // Optional: Used as a replacement in the formatted character data string // passed in Output. D Replacement6... D Like(RXS_Var1Kv_t) Const D Options(*Varsize: *Nopass) // Optional: Used as a replacement in the formatted character data string // passed in Output. D Replacement7... D Like(RXS_Var1Kv_t) Const D Options(*Varsize: *Nopass) // Optional: Used as a replacement in the formatted character data string // passed in Output. D Replacement8... D Like(RXS_Var1Kv_t) Const D Options(*Varsize: *Nopass) // Optional: Used as a replacement in the formatted character data string // passed in Output. D Replacement9... D Like(RXS_Var1Kv_t) Const D Options(*Varsize: *Nopass) // Optional: Used as a replacement in the formatted character data string // passed in Output. D Replacement10... D Like(RXS_Var1Kv_t) Const D Options(*Varsize: *Nopass) ``` ## Example Code ### IBM i 6.1+ #### Example 1: Write to Job Log Without Placeholders ```rpgle *-------------------------------------------------------------- * This example uses RXS_JobLog() in the most simple form to just * write a basic character string to the job log. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB D JobLogMsg S Like(RXS_Var1Kv_t) /free JobLogMsg = 'Hello world!'; RXS_JobLog( JobLogMsg ); //Job Log Output: Hello world! *INLR = *ON; /end-free ``` #### Example 2: Write to Job Log With a Single Placeholder ```rpgle *-------------------------------------------------------------- * This example uses RXS_JobLog() with a tring which contains a * single replacement placeholder. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB D JobLogMsg S Like(RXS_Var1Kv_t) /free JobLogMsg = 'Hello %s!'; RXS_JobLog( JobLogMsg : 'Bob'); //Job Log Output: Hello Bob! *INLR = *ON; /end-free ``` #### Example 3: Write to Job Log With Multiple Placeholders ```rpgle *-------------------------------------------------------------- * This example uses RXS_JobLog() with a string which contains * multiple replacement placeholders. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB D JobLogMsg S Like(RXS_Var1Kv_t) /free JobLogMsg = 'Hello %s! Your lucky number is: %s'; RXS_JobLog( JobLogMsg : 'Bob' : %Char(7) ); //Job Log Output: Hello Bob! Your lucky number is: 7 *INLR = *ON; /end-free ``` --- # RXS_OpenDom() > Initializes DOM-based XML parsing from a character field or IFS stream file, enabling XPath-based node navigation. This subprocedure initializes DOM parsing for a specified chunk of XML. ## Subprocedure Prototype ### IBM i 6.1+ ```rpgle // Returns an RXS_ParseDOMDS_t which contains information and pointers used // by subsequent DOM parsing APIs. D RXS_OpenDom PR Extproc('RXS_OpenDom') Opdesc D Like(RXS_ParseDOMDS_t) // Chunk of XML to be used for subsequent DOM operations. D Xml Like(RXS_Var16Mv_t) Const D Options(*Omit:*Varsize) // Holds RXS_OpenDomDS_t used to set up initial DOM parsing options. D DS LikeDS(RXS_OpenDomDS_t) D Options(*Nopass:*Varsize) ``` ## Example Code ### IBM i 6.1+ #### Example 1 ```rpgle *-------------------------------------------------------------- * This example demonstrates configuring DOM parsing using a RXS_ParseDOMDS_t * datastructure. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB D OpenDomDS DS LikeDS(RXS_OpenDOMDS_t) D RootDomDS DS LikeDS(RXS_ParseDOMDS_t) /free RXS_ResetDS( OpenDomDs : RXS_DS_TYPE_OPENDOM ); RXS_ResetDS( RootDomDs : RXS_DS_TYPE_PARSEDOM ); OpenDomDs.InputCcsid = RXS_CCSID_UTF8; RootDomDS = RXS_OpenDom( gXmlResponse : OpenDomDS ); gXPath = RXS_XPath( '/*:Envelope/*:Body/*:FahrenheitToCelsius' + 'Response/*:FahrenheitToCelsiusResult' ); gCelsius = %Dec( RXS_ParseDomToText( gXPath : RootDomDS ) : 11 : 7 ); RXS_CloseDom( RootDomDS ); *INLR = *ON; /end-free ``` ## Data Structures ### RXS_OpenDomDS_t ```rpgle D RXS_OpenDomDS_t... D DS Qualified Template Inz D ReturnedErrorInfo... D LikeDS(RXS_ReturnedErrorInfoDS_t) Inz D OnErrorMessageType... D 10I 0 // Specifies the CCSID of the XML being parsed. D InputCcsid... D 10I 0 // Specifies the CCSID the parsed data will be converted to. D OutputCcsid... D 10I 0 // Specifies an IFS path to an XML file to parse instead of the Input parm. D Stmf... D Like(RXS_Var1Kv_t) ``` --- # RXS_Parse() > Event-based XML parser that calls a handler subprocedure for element begin, content, end, and attribute events. This subprocedure is used to set up XML parsing. Use of this subprocedure requires an XML handler subprocedure to also be written. The events recognized by the XML parser are: | Event | Format | Example | | ----- |-| ------ | | Element Begin | `>` | `Request>` | | Element Content | `/` | `Request/Item/` | | Element End | `/>` | `Request/>` | | Attribute | `@` | `Request/Item@Attribute` | The Element Content and Attribute events will return data, which can be retrieved with [RXS_STR()](https://isupport.katointegrations.com/rxs/3.2/rxs_str.md). ## Subprocedure Prototype ### IBM i 6.1+ ```rpgle D RXS_Parse... D PR Extproc('RXS_Parse') // Holds the XML data to be passed to the parsing subprocedure(s). Will be // ignored if the Stmf subfield of the DS parameter is set. D Input Like(RXS_Var16Mv_t) D Options(*Varsize) // Holds a RXS_ParseDS_t data structure which controls how RXS_Parse() // functions. D ParseDS Likeds(RXS_ParseDS_t) ``` ## Example Code ### IBM i 7.1+ #### Example 1: Simple Parse ```rpgle *-------------------------------------------------------------- * This example parses a simple XML structure stored in the field * 'XML' and stores the data contained in nodes and * in the corresponding global fields. * * At a high level, the XML is passed into the XmlHandler() * subprocedure in small chunks. Then, a SELECT block is used to * detect whether or not the current chunk of XML matches one * you'd like to handle. If it does, you can extract the data from * an element of attribute using RXS_STR(). * * Once the XML has been entirely passed through XmlHander(), control * returns to the main part of the program. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB D XmlHandler PR D pType 10A Value D pXPath 1024A Value Varying D pData * Value D pDataLen 10I 0 Value D ParseDS DS LikeDS(RXS_ParseDS_t) D XML S Like(RXS_Var64Kv_t) D Node1 S Like(RXS_Var1Kv_t) D Node2 S Like(RXS_Var1Kv_t) /free XML = '' + 'HelloWorld'; RXS_ResetDS( ParseDS : RXS_DS_TYPE_PARSE ); ParseDS.GlobalHandler = %Paddr( XmlHandler ); RXS_Parse( XML : ParseDS ); RXS_JobLog( 'Node 1: %s' : Node1 ); RXS_JobLog( 'Node 2: %s' : Node2 ); *INLR = *ON; /end-free P XmlHandler B D XmlHandler PI D pType 10A Value D pXPath 1024A Value Varying D pData * Value D pDataLen 10I 0 Value /free select; when pXPath = '/Root/Node1/'; Node1 = RXS_STR( pData : pDataLen ); when pXPath = '/Root/Node2/'; Node2 = RXS_STR( pData : pDataLen ); endsl; /end-free P E ``` ### IBM i 6.1 #### Example 1: Simple Parse ```rpgle *-------------------------------------------------------------- * This example parses a simple XML structure stored in the field * 'XML' and stores the data contained in nodes and * in the corresponding global fields. * * At a high level, the XML is passed into the XmlHandler() * subprocedure in small chunks. Then, a SELECT block is used to * detect whether or not the current chunk of XML matches one * you'd like to handle. If it does, you can extract the data from * an element of attribute using RXS_STR(). * * Once the XML has been entirely passed through XmlHander(), control * returns to the main part of the program. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /define RXSV6R1 /copy QRPGLECPY,RXSCB D XmlHandler PR D pType 10A Value D pXPath 1024A Value Varying D pData * Value D pDataLen 10I 0 Value D ParseDS DS LikeDS(RXS_ParseDS_t) D XML S Like(RXS_Var64Kv_t) D Node1 S Like(RXS_Var1Kv_t) D Node2 S Like(RXS_Var1Kv_t) /free XML = '' + 'HelloWorld'; RXS_ResetDS( ParseDS : RXS_DS_TYPE_PARSE ); ParseDS.GlobalHandler = %Paddr( XmlHandler ); RXS_Parse( XML : ParseDS ); RXS_JobLog( 'Node 1: %s' : Node1 ); RXS_JobLog( 'Node 2: %s' : Node2 ); *INLR = *ON; /end-free P XmlHandler B D XmlHandler PI D pType 10A Value D pXPath 1024A Value Varying D pData * Value D pDataLen 10I 0 Value /free select; when pXPath = '/root/node1/'; RXS_STR( Node1 : pData : pDataLen ); when pXPath = '/root/node2/'; RXS_STR( Node2 : pData : pDataLen ); endsl; /end-free P E ``` ## Data Structures ### RXS_ParseDS_t ```rpgle D RXS_ParseDS_t DS Qualified Template Inz D ReturnedErrorInfo... D Like(RXS_ReturnedErrorInfoDS_t) Inz D OnErrorMessageType... D 10I 0 // Holds a PROCPTR to an XmlHandler subprocedure used to handle all // possible XML events. D GlobalHandler... D * Procptr // Holds a PROCPTR to an XmlHandler subprocedure which will only respond to // XML content events. D ElementContentHandler... D * Procptr // Holds a PROCPTR to an XmlHandler subprocedure which will only respond to // XML begin events. D ElementBeginHandler... D * Procptr // Holds a PROCPTR to an XmlHandler subprocedure which will only respond to // XML end events. D ElementEndHandler... D * Procptr // Holds a PROCPTR to an XmlHandler subprocedure which will only respond to // XML attribute events. D AttributeHandler... D * Procptr // Controls whether namespaces are factored into XML parsing - if RXS_NO, // they will be ignored. D IncludeNamespaces... D N // Specifies the CCSID of the XML being parsed. D InputCcsid... D 10I 0 // Specifies the CCSID the parsed data will be converted to. D OutputCcsid... D 10I 0 // Specifies an IFS path to an XML file to parse instead of the Input parm. D Stmf... D Like(RXS_Var1Kv_t) ``` --- # RXS_ParseDomToDom() > Navigates the DOM to a node matching an XPath expression and returns a child DOM handle for further traversal. This subprocedure retrieves a new RXS_ParseDomDS_t data structure from a parent XML structure, allowing you to retrieve and work with a subset of a larger XML document. ## Subprocedure Prototype ### IBM i 6.1+ ```rpgle // Returns an RXS_ParseDomDS_t which contains information and pointers used // by subsequent DOM parsing APIs. D RXS_ParseDomToDom... D PR Extproc('RXS_ParseDomToDom') Opdesc D Like(RXS_ParseDomDS_t) // XPath used to determine which nodes are retrieved into the // RXS_ParseDomDS_t return data structure. D XPath Like(RXS_Var8Kv_t) Const D Options(*Varsize) // RXS_ParseDomDS_t data structure, e.g. the "parent" structure. D DS Like(RXS_ParseDomDS_t) D Options(*Varsize) ``` ## Example Code ### IBM i 7.1+ #### Example 1 ```rpgle *-------------------------------------------------------------- * This example demonstrates retrieving a DOM from a specified XPath * and storing it in a RXS_ParseDomDS_t datastructure for further * processing. * This example uses IBM i 7.1+ prototypes for most calls; refer to * the individual documentation for these subprocedures for the * 6.1 prototypes. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB D gRootDomDS DS LikeDS(RXS_OpenDomDS_t) D gBookDomDS DS LikeDS(RXS_ParseDomDS_t) D gXml S Like(RXS_Var8Kv_t) D gXPath S Like(RXS_Var1Kv_t) /free RXS_ResetDS( gRootDomDS : RXS_DS_TYPE_OPENDOM ); RXS_ResetDS( gBookDomDS : RXS_DS_TYPE_PARSEDOM ); gXml = RXS_GetStdIn(); gRootDomDS = RXS_OpenDom( gXml ); gXPath = RXS_XPath( '/*:bookstore/*:book' ); gBookDomDS = RXS_ParseDomToDom( gXPath : gRootDomDS ); *INLR = *ON; /end-free ``` ## Data Structures ### RXS_ParseDomDS_t ```rpgle D RXS_ParseDomDS_t... D DS Qualified Template Inz D ReturnedErrorInfo... D LikeDS(RXS_ReturnedErrorInfoDS_t) Inz D OnErrorMessageType... D 10I 0 // Specifies the CCSID of the XML being parsed. D InputCcsid... D 10I 0 // Specifies the CCSID the parsed data will be converted to. D OutputCcsid... D 10I 0 // Specifies an IFS path to an XML file to parse instead of the Input parm. D Stmf... D Like(RXS_Var1Kv_t) // Contains the current count of XML nodes tracked by this data structure. D NodeCount 10U 0 D NodeType 10I 0 // Internal use only D xml@ * // Internal use only D doc@ * // Internal use only D context@ * // Internal use only D dict@ * // Internal use only D current@ * // Internal use only D parent@ * // Internal use only D Reserved 4096A ``` --- # RXS_ParseDomToText() > Extracts the text content of an XML node matching an XPath expression. This subprocedure retrieves the text result of a specific XPath. ## Subprocedure Prototype ### IBM i 7.1+ ```rpgle // Returns the text retrieved from the specified XPath. D RXS_ParseDomToText... D PR Extproc('RXS_ParseDomToText') Opdesc D Like(RXS_Var16Mv_t) D Rtnparm // XPath used to determine which nodes are retrieved into the // RXS_ParseDomDS_t return data structure. D XPath Like(RXS_Var8Kv_t) Const D Options(*Varsize) // RXS_ParseDomDS_t data structure, e.g. the "parent" structure. D DS Like(RXS_ParseDomDS_t) D Options(*Varsize) ``` ### IBM i 6.1 ```rpgle D RXS_ParseDomToText... D PR Extproc('RXS_ParseDomToText') Opdesc // Holds the text retrieved from the specified XPath. D Output Like(RXS_Var16Mv_t) D Options(*Varsize) // XPath used to determine which nodes are retrieved into the // RXS_ParseDomDS_t return data structure. D XPath Like(RXS_Var8Kv_t) Const D Options(*Varsize) // RXS_ParseDomDS_t data structure, e.g. the "parent" structure. D DS Like(RXS_ParseDomDS_t) D Options(*Varsize) ``` ## Example Code ### IBM i 7.1+ #### Example 1 ```rpgle *-------------------------------------------------------------- * This example demonstrates retrieving a text value from a specified * XPath and storing it in a character field. * This example uses IBM i 7.1+ prototypes for most calls; refer to * the individual documentation for these subprocedures for the * 6.1 prototypes. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB D gRootDomDS DS LikeDS(RXS_OpenDomDS_t) D gXml S Like(RXS_Var8Kv_t) D gData S Like(RXS_Var8Kv_t) /free RXS_ResetDS( gRootDomDS : RXS_DS_TYPE_OPENDOM ); gXml = RXS_GetStdIn(); gRootDomDS = RXS_OpenDom( gXml ); gXPath = RXS_XPath( '/*:bookstore/*:book' ); gData = RXS_ParseDomToText( gXPath : gRootDomDS ); *INLR = *ON; /end-free ``` ## Data Structures ### RXS_ParseDomDS_t ```rpgle D RXS_ParseDomDS_t... D DS Qualified Template Inz D ReturnedErrorInfo... D LikeDS(RXS_ReturnedErrorInfoDS_t) Inz D OnErrorMessageType... D 10I 0 // Specifies the CCSID of the XML being parsed. D InputCcsid... D 10I 0 // Specifies the CCSID the parsed data will be converted to. D OutputCcsid... D 10I 0 // Specifies an IFS path to an XML file to parse instead of the Input parm. D Stmf... D Like(RXS_Var1Kv_t) // Contains the current count of XML nodes tracked by this data structure. D NodeCount 10U 0 D NodeType 10I 0 // Internal use only D xml@ * // Internal use only D doc@ * // Internal use only D context@ * // Internal use only D dict@ * // Internal use only D current@ * // Internal use only D parent@ * // Internal use only D Reserved 4096A ``` --- # RXS_ParseDomToXml() > Serializes an XML node matching an XPath expression back to an XML string. This subprocedure retrieves the raw XML from a specific XPath. ## Subprocedure Prototype ### IBM i 7.1+ ```rpgle // Returns the XML subsection retrieved by the specified XPath. D RXS_ParseDomToXml... D PR Extproc('RXS_ParseDomToXml') Opdesc D Like(RXS_Var16Mv_t) D Rtnparm // XPath used to determine which nodes are retrieved into the // RXS_ParseDomDS_t return data structure. D XPath Like(RXS_Var8Kv_t) Const D Options(*Varsize) // RXS_ParseDomDS_t data structure, e.g. the "parent" structure. D DS Like(RXS_ParseDomDS_t) D Options(*Varsize) ``` ### IBM i 6.1 ```rpgle D RXS_ParseDomToXml... D PR Extproc('RXS_ParseDomToXml') Opdesc // Holds the XML subsection retrieved by the specified XPath. D Output Like(RXS_Var16Mv_t) D Options(*Varsize) // XPath used to determine which nodes are retrieved into the // RXS_ParseDomDS_t return data structure. D XPath Like(RXS_Var8Kv_t) Const D Options(*Varsize) // RXS_ParseDomDS_t data structure, e.g. the "parent" structure. D DS Like(RXS_ParseDomDS_t) D Options(*Varsize) ``` ## Example Code ### IBM i 7.1+ #### Example 1 ```rpgle *-------------------------------------------------------------- * This example demonstrates retrieving the raw XML data from a specified * XPath and storing it in a character field. * This example uses IBM i 7.1+ prototypes for most calls; refer to * the individual documentation for these subprocedures for the * 6.1 prototypes. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB D gRootDomDS DS LikeDS(RXS_OpenDomDS_t) D gXml S Like(RXS_Var8Kv_t) D gData S Like(RXS_Var8Kv_t) /free RXS_ResetDS( gRootDomDS : RXS_DS_TYPE_OPENDOM ); gXml = RXS_GetStdIn(); gRootDomDS = RXS_OpenDom( gXml ); gXPath = RXS_XPath( '/*:bookstore/*:book' ); gData = RXS_ParseDomToXml( gXPath : gRootDomDS ); *INLR = *ON; /end-free ``` ## Data Structures ### RXS_ParseDomDS_t ```rpgle D RXS_ParseDomDS_t... D DS Qualified Template Inz D ReturnedErrorInfo... D LikeDS(RXS_ReturnedErrorInfoDS_t) Inz D OnErrorMessageType... D 10I 0 // Specifies the CCSID of the XML being parsed. D InputCcsid... D 10I 0 // Specifies the CCSID the parsed data will be converted to. D OutputCcsid... D 10I 0 // Specifies an IFS path to an XML file to parse instead of the Input parm. D Stmf... D Like(RXS_Var1Kv_t) // Contains the current count of XML nodes tracked by this data structure. D NodeCount 10U 0 D NodeType 10I 0 // Internal use only D xml@ * // Internal use only D doc@ * // Internal use only D context@ * // Internal use only D dict@ * // Internal use only D current@ * // Internal use only D parent@ * // Internal use only D Reserved 4096A ``` --- # RXS_ProcessStmf() > Processes an IFS stream file in chunks, calling a handler subprocedure for each chunk. This subprocedure can be used to create, copy, move, or delete a specified IFS stream file. ## Subprocedure Prototype ### IBM i 6.1+ ```rpgle D RXS_ProcessStmf... D PR Extproc('RXS_ProcessStmf') Opdesc // Contains the IFS file path as well as configuration options to control // how the data is written. May be one of a few possible data structures, // listed below. D DS Like(RXS_Var64K_t) D Options(*Varsize) ``` ## Example Code ### IBM i 6.1+ #### Example 1: Create an IFS Stream File ```rpgle *-------------------------------------------------------------- * This example code creates a stream file named new_file.xml in * the IFS directory /tmp with CCSID 819. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB D CreateStmfDS DS LikeDS(RXS_CreateStmfDS_t) /free RXS_ResetDS( CreateStmfDS : RXS_DS_TYPE_CREATESTMF ); CreateStmfDS.Stmf = '/tmp/new_file.xml'; CreateStmfDS.Ccsid = RXS_CCISD_ISO88591; RXS_ProcessStmf( CreateStmfDS ); *INLR = *ON; /end-free ``` #### Example 2: Copy an IFS Stream File ```rpgle *-------------------------------------------------------------- * This example code copies an IFS file from /tmp/new_file.xml to * /tmp/copied_new_file.xml. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB D CopyStmfDS DS LikeDS(RXS_CopyStmfDS_t) /free RXS_ResetDS( CopyStmfDS : RXS_DS_TYPE_COPYSTMF ); CopyStmfDS.FromStmf = '/tmp/new_file.xml'; CopyStmfDS.ToStmf = '/tmp/copied_new_file.xml'; RXS_ProcessStmf( CopyStmfDS ); *INLR = *ON; /end-free ``` #### Example 3: Move an IFS Stream File ```rpgle *-------------------------------------------------------------- * This example code copies an IFS file from /tmp/new_file.xml * to /tmp/moved_new_file.xml. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB D MoveStmfDS DS LikeDS(RXS_MoveStmfDS_t) /free RXS_ResetDS( MoveStmfDS : RXS_DS_TYPE_MOVESTMF ); MoveStmfDS.FromStmf = '/tmp/new_file.xml'; MoveStmfDS.ToStmf = '/tmp/moved_new_file.xml'; RXS_ProcessStmf( MoveStmfDS ); *INLR = *ON; /end-free ``` #### Example 4: Delete an IFS Stream File ```rpgle *-------------------------------------------------------------- * This example code deletes an IFS file named /tmp/moved_new_file.xml. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB D DeleteStmfDS DS LikeDS(RXS_DeleteStmfDS_t) /free RXS_ResetDS( DeleteStmfDS : RXS_DS_TYPE_DELETESTMF ); DeleteStmfDS.Stmf = '/tmp/moved_new_file.xml'; RXS_ProcessStmf( DeleteStmfDS ); *INLR = *ON; /end-free ``` ## Data Structures ### RXS_CopyStmfDS_t ```rpgle D RXS_CopyStmfDS_t... D DS Qualified Template Inz D ReturnedErrorInfo... D LikeDS(RXS_ReturnedErrorInfoDS_t) Inz D OnErrorMessageType... D 10I 0 // Specify the IFS file path to copy from. D FromStmf LIKE(RXS_Var1Kv_t) // Specify the IFS file path to copy to. D ToStmf LIKE(RXS_Var1Kv_t) // Specify the CCSID the copied file will use. D ToCcsid 10I 0 // Internal use only D Reserved 2048A ``` ### RXS_CreateStmfDS_t ```rpgle D RXS_CreateStmfDS_t... D DS Qualified Template Inz D ReturnedErrorInfo... D LikeDS(RXS_ReturnedErrorInfoDS_t) Inz D OnErrorMessageType... D 10I 0 // Specify IFS path where the file will be created. D Stmf LIKE(RXS_Var1Kv_t) // Specify the CCSID to create the file with. D Ccsid 10I 0 // Internal use only D Reserved 2048A ``` ### RXS_DeleteStmfDS_t ```rpgle D RXS_DeleteStmfDS_t... D DS Qualified Template Inz D ReturnedErrorInfo... D LikeDS(RXS_ReturnedErrorInfoDS_t) Inz D OnErrorMessageType... D 10I 0 // Specify the IFS file path to delete. D Stmf LIKE(RXS_Var1Kv_t) // Internal use only D Reserved 2048A ``` ### RXS_MoveStmfDS_t ```rpgle D RXS_MoveStmfDS_t... D DS Qualified Template Inz D ReturnedErrorInfo... D LikeDS(RXS_ReturnedErrorInfoDS_t) Inz D OnErrorMessageType... D 10I 0 // Specify the IFS file path to move from. D Stmf LIKE(RXS_Var1Kv_t) // Specify an IFS file directory to move to. Note: You should only specify // a directory path, not a full path to a file. D ToDir LIKE(RXS_Var1Kv_t) // Internal use only D Reserved 2048A ``` --- # RXS_PutEnvVar() > Sets an Apache environment variable from within an RPG program. This subprocedure is used to set a job-level environment variable, or to modify an already existing environment variable. ## Subprocedure Prototype ### IBM i 6.1 ```rpgle D RXS_PutEnvVar... D PR // Specifies the environment variable to be set. Must be in name=value // format. D EnvVar Like(RXS_Var16Mv_t) Const D Options(*Varsize) ``` ## Example Code ### IBM i 6.1+ #### Example 1: Setting an Environment Variable ```rpgle *-------------------------------------------------------------- * This example code sets an environment variable. You can view * the results by running the following command: * WRKENVVAR *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB D EnvVar S Like(RXS_Var1Kv_t) D Data S Like(RXS_Var1Kv_t) /free EnvVar = 'IS_RPG_AWESOME=Yes'; RXS_PutEnvVar( EnvVar ); *INLR = *ON; /end-free ``` --- # RXS_PutStdOut() > Writes data to the HTTP response body (stdout); used to send output from hosted web service programs. This subprocedure is used to output (to standard out) data. Typically, this would be used in a scenario where you are providing a webservice, and would be used to output XML retrieved via [RXS_GetComposeBuffer()](https://isupport.katointegrations.com/rxs/3.2/rxs_getcomposebuffer.md). ## Subprocedure Prototype ### IBM i 6.1+ ```rpgle D RXS_PutStdOut... D PR Extproc('RXS_PutStdOut') // Data to be written to "standard out", i.e. to a web browser or to a web // service which initiated the incoming request as a client. D Input Like(RXS_Var16Mv_t) D Options(*Varsize) Const // Optional RXS_PutStdOutDS_t to allow for CCSID conversion during output. D pDS Like(RXS_Var64K_t) D Options(*Varsize:*Nopass) ``` ## Example Code ### IBM i 6.1+ #### Example 1 ```rpgle *-------------------------------------------------------------- * This example code writes the content of the field gXml to STDOUT. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB D gXML S Like(RXS_Var1Kv_t) /free gXml = 'Example XML'; RXS_PutStdOut( gXml ); *INLR = *ON; /end-free ``` #### Example 2 ```rpgle *-------------------------------------------------------------- * This example code specifies the header content type as XML, * then sends the data to STDOUT. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB D putStdOutDS DS LikeDS(RXS_PutStdOutDS_t) D gXML S Like(RXS_Var1Kv_t) /free RXS_ResetDS( PutStdOutDS : RXS_DS_TYPE_PUTSTDOUT ); gXml = 'Example XML'; PutStdOutDS.HeaderContentType = 'text/xml'; RXS_PutStdOut( gXml : PutStdOutDS ); *INLR = *ON; /end-free ``` #### Example 3 ```rpgle *-------------------------------------------------------------- * This example code specifies the header content type as XML, and * specifies the IFS file from which data will be read to STDOUT. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB D putStdOutDS DS LikeDS(RXS_PutStdOutDS_t) /free RXS_ResetDS( PutStdOutDS : RXS_DS_TYPE_PUTSTDOUT ); PutStdOutDS.HeaderContentType = 'text/xml'; PutStdOutDS.Stmf = '/tmp/over16mb.xml'; RXS_PutStdOut( *Omit : PutStdOutDS ); *INLR = *ON; /end-free ``` #### Example 4 ```rpgle *-------------------------------------------------------------- * This example code specifies the header content type as XML, and * sets a header status code and text to communicate an HTTP error, * then sends the XML to STDOUT. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB D putStdOutDS DS LikeDS(RXS_PutStdOutDS_t) D gXML S Like(RXS_Var1Kv_t) /free RXS_ResetDS( PutStdOutDS : RXS_DS_TYPE_PUTSTDOUT ); gXml = 'Example XML'; PutStdOutDS.HeaderStatusCode = 500; PutStdOutDS.HeaderStatusText = 'SOAP Fault'; PutStdOutDS.HeaderContentType = 'text/xml'; RXS_PutStdOut( gXml : PutStdOutDS ); *INLR = *ON; /end-free ``` #### Example 5 ```rpgle *-------------------------------------------------------------- * This example code specifies the header content type as XML, and * sets a sets a custom header "Prefer", then sends the XML to STDOUT. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB D putStdOutDS DS LikeDS(RXS_PutStdOutDS_t) D gXML S Like(RXS_Var1Kv_t) /free RXS_ResetDS( PutStdOutDS : RXS_DS_TYPE_PUTSTDOUT ); gXml = 'Example XML'; PutStdOutDS.HeaderContentType = 'text/xml'; PutStdOutDS.CustomHeaderName(1) = 'Prefer'; PutStdOutDS.CustomHeaderValue(1) = 'Return=representation'; RXS_PutStdOut( gXml : PutStdOutDS ); *INLR = *ON; /end-free ``` ## Data Structures ### RXS_PutStdOutDS_t ```rpgle D RXS_PutStdOutDS_t... D DS Qualified Template Inz D ReturnedErrorInfo... D LikeDS(RXS_ReturnedErrorInfoDS_t) Inz D DataStructureType... D 5I 0 Inz(RXS_DS_TYPE_PUTSTDOUT) D OnErrorMessageType... D 5I 0 // The contents of the Input parameter are converted from the job CCSID to // this CCSID before being sent to standard out. D Ccsid 10I 0 // Specifies IFS path to a stream file whose contents are to be sent to // STDOUT. D Stmf Like(RXS_Var1Kv_t) // The HTTP Status code to be sent in the response. A sucessful response is // typically "200". D HeaderStatusCode... D 10I 0 // The HTTP Status text to be sent in the response. This is also known as // the reason phrase. A sucessful response is typically "OK". D HeaderStatusText... D Like(RXS_Var1Kv_t) // The HTTP content type to be sent with the response. The most common // content type for web services is "text/xml". There is no assumed default // value and if this value is not supplied via this data structure, then // the content type is usually required to be supplied in the Input // parameter and it must be followed by two line control characters. D HeaderContentType... D Like(RXS_Var1Kv_t) // Specifies the name of up to 50 custom HTTP headers sent with the // response. D CustomHeaderName... D 64A Varying Dim(50) // Specifies the value of up to 50 corresponding CustomHeaderName's. D CustomHeaderValue... D Like(RXS_Var1Kv_t) Dim(50) ``` --- # RXS_PutStmf() > Writes data from an RPG variable to an IFS stream file. This subprocedure writes the contents of a field up to 16MB in size to an IFS stream file. ## Subprocedure Prototype ### IBM i 6.1+ ```rpgle D RXS_PutStmf... D PR Extproc('RXS_PutStmf') Opdesc // Data to write to the IFS stream file. D Input Like(RXS_Var16Mv_t) Const D Options(*Varsize) // RXS_PutStmfDS_t used to configure the write operation, such as the file // path to write to. D DS Likeds(RXS_PutStmfDS_t) ``` ## Example Code ### IBM i 7.1+ #### Example 1: Output Character String to IFS stream file ```rpgle *-------------------------------------------------------------- * This example code writes the value The quick brown fox * jumps over the lazy dog to the file /tmp/rxs_putstmf.txt *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB D PutStmfDS DS LikeDS(RXS_PutStmfDS_t) D Inz(*LikeDS) D Data S Like(RXS_Var64Kv_t) /free Data = 'The quick brown fox jumps over the lazy dog'; RXS_ResetDS( PutStmfDS : RXS_DS_TYPE_PUTSTMF ); PutStmfDS.Stmf = '/tmp/rxs_putstmf.txt'; RXS_PutStmf( Data : PutStmfDS ); *INLR = *ON; /end-free ``` ## Data Structures ### RXS_PutStmfDS_t ```rpgle D RXS_PutStmfDS_t... D DS Qualified Template Inz D ReturnedErrorInfo... D LikeDS(RXS_ReturnedErrorInfoDS_t) Inz D OnErrorMessageType... D 10I 0 // Specifies an IFS path to a stream file to write to. D Stmf LIKE(RXS_Var1Kv_t) // Determines whether to append the data to the file (RXS_YES), or to // overwrite the file (RXS_NO). // Valid values: RXS_YES, RXS_NO // Default: RXS_NO D Append N // The CCSID of the IFS stream file to be created/written to. D StmfCcsid 10I 0 // The CCSID of the data being passed. Note: This is typically optional as // internally RXS_PutStmf() will assume the data you're passing is the same // CCSID as the current job. D InputCcsid 10I 0 // Internal use only D InputPointer... D * // Internal use only D InputLength 10I 0 ``` --- # RXS_ResetDS() > Resets all fields in an RXS data structure to their default values. This subprocedure initializes a data structure with default values. Always intialize a data structure before use and always use this API instead of the RESET opcode. ## Subprocedure Prototype ### IBM i 6.1+ ```rpgle D RXS_ResetDS... D PR Extproc('RXS_ResetDS') Opdesc // Holds the data structure to be initialized with default values. D DS Like(RXS_Var512K_t) D Options(*Varsize) // The type of data structure to be initialized with default values. D TypeOfDS 5I 0 Const ``` ## Example Code ### IBM i 6.1+ #### Example 1: Intialize all current RXS3 data structure types ```rpgle *-------------------------------------------------------------- * This example code initializes most of the current RXS3 data * structure types using RXS_ResetDS(). *-------------------------------------------------------------- D gComposeDS DS LikeDS(RXS_ComposeDS_t) D gTransmitDS DS LikeDS(RXS_TransmitDS_t) D gParseDS DS LikeDS(RXS_ParseDS_t) D gCatchThrowErrorDS... D DS LikeDS(RXS_CatchThrowErrorDS_t) D gConvertBase64DS... D DS LikeDS(RXS_ConvertBase64DS_t) D gConvertCaseDS DS LikeDS(RXS_ConvertCaseDS_t) D gConvertCcsidDS... D DS LikeDS(RXS_ConvertCcsidDS_t) D gConvertUrlPercentDS... D DS LikeDS(RXS_ConvertUrlPercentDS_t) D gConvertUserDefinedDS... D DS LikeDS(RXS_ConvertUserDefinedDS_t) D gConvertXmlEntitiesDS... D DS LikeDS(RXS_ConvertXmlEntitiesDS_t) D gCopyStmfDS DS LikeDS(RXS_CopyStmfDS_t) D gCreateStmfDS DS LikeDS(RXS_CreateStmfDS_t) D gDeleteStmfDS DS LikeDS(RXS_DeleteStmfDS_t) D gGetStmfDS DS LikeDS(RXS_GetStmfDS_t) D gPutStmfDS DS LikeDS(RXS_PutStmfDS_t) D gMoveStmfDS DS LikeDS(RXS_MoveStmfDS_t) D gOpenDomDS DS LikeDS(RXS_OpenDomDS_t) D gParseDomDS DS LikeDS(RXS_ParseDomDS_t) D gGetStdInDS DS LikeDS(RXS_GetStdInDS_t) D gPutStdOutDS DS LikeDS(RXS_PutStdOutDS_t) D gAesCryptDS DS LikeDS(RXS_AesCryptDS_t) D gMd5CryptDS DS LikeDS(RXS_Md5CryptDS_t) D gShaCryptDS DS LikeDS(RXS_ShaCryptDS_t) D gXsdValidationDS... D DS LikeDS(RXS_XsdValidationDS_t) /free RXS_ResetDS( gComposeDS : RXS_DS_TYPE_COMPOSE ); RXS_ResetDS( gTransmitDS : RXS_DS_TYPE_TRANSMIT ); RXS_ResetDS( gParseDS : RXS_DS_TYPE_PARSE ); RXS_ResetDS( gCatchThrowErrorDS : RXS_DS_TYPE_CATCHTHROWERROR ); RXS_ResetDS( gConvertBase64DS : RXS_DS_TYPE_CONVERTBASE64 ); RXS_ResetDS( gConvertCaseDS : RXS_DS_TYPE_CONVERTCASE ); RXS_ResetDS( gConvertCcsidDS : RXS_DS_TYPE_CONVERTCCSID ); RXS_ResetDS( gConvertUrlPercentDS : RXS_DS_TYPE_CONVERTURLPERCENT ); RXS_ResetDS( gConvertUserDefinedDS : RXS_DS_TYPE_CONVERTUSERDEFINED ); RXS_ResetDS( gConvertXmlEntitiesDS : RXS_DS_TYPE_CONVERTXMLENTITIES ); RXS_ResetDS( gCopyStmfDS : RXS_DS_TYPE_COPYSTMF ); RXS_ResetDS( gCreateStmfDS : RXS_DS_TYPE_CREATESTMF ); RXS_ResetDS( gDeleteStmfDS : RXS_DS_TYPE_DELETESTMF ); RXS_ResetDS( gGetStmfDS : RXS_DS_TYPE_GETSTMF ); RXS_ResetDS( gPutStmfDS : RXS_DS_TYPE_PUTSTMF ); RXS_ResetDS( gMoveStmfDS : RXS_DS_TYPE_MOVESTMF ); RXS_ResetDS( gOpenDomDS : RXS_DS_TYPE_OPENDOM ); RXS_ResetDS( gParseDomDS : RXS_DS_TYPE_PARSEDOM ); RXS_ResetDS( gGetStdInDS : RXS_DS_TYPE_GETSTDIN ); RXS_ResetDS( gPutStdOutDS : RXS_DS_TYPE_PUTSTDOUT ); RXS_ResetDS( gAesCryptDS : RXS_DS_TYPE_AESCRYPT ); RXS_ResetDS( gMd5CryptDS : RXS_DS_TYPE_MD5CRYPT ); RXS_ResetDS( gShaCryptDS : RXS_DS_TYPE_SHACRYPT ); RXS_ResetDS( gXsdValidationDS : RXS_DS_TYPE_XSDVALIDATION ); /end-free ``` --- # RXS_StartComposeEngine() > Initializes the RXS template compose engine, loading a compiled template (.tpl) file. This subprocedure initializes the compose engine with a specific template file. This is utilized primarily to build XML but could be used to build any type of character data. ## Subprocedure Prototype ### IBM i 6.1+ ```rpgle D RXS_StartComposeEngine... D PR Extproc('RXS_StartComposeEngine') D Opdesc // Pass in an RXS_ComposeDS_t to control how the composition engine // functions. D ComposeDS Likeds(RXS_ComposeDS_t) D Options(*Varsize) ``` ## Example Code ### IBM i 6.1+ #### Example 1 ```rpgle *-------------------------------------------------------------- * This example code initializes the composition engine for the EXAMPLE template and * configures it with the procedure address for the Template procedure. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB /copy QRPGLETPL,EXAMPLE D ComposeDS DS LikeDS(RXS_ComposeDS_t) /free RXS_ResetDS( ComposeDS : RXS_DS_TYPE_COMPOSE ); ComposeDS.TemplateProcedure = %Paddr(Template); RXS_StartComposeEngine( ComposeDS ); *INLR = *ON; /end-free P Template B D PI D p Like(RXS_TEMPLATE_PARM) /copy QRPGLETPL,EXAMPLE P E ``` #### Example 2 ```rpgle *-------------------------------------------------------------- * This example code initializes the composition engine for the EXAMPLE template and * configures it with the procedure address for the Template procedure. It also * sets configuration values to trim whitespace from template lines and to * omit line control characters. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB /copy QRPGLETPL,EXAMPLE D ComposeDS DS LikeDS(RXS_ComposeDS_t) /free RXS_ResetDS( ComposeDS : RXS_DS_TYPE_COMPOSE ); ComposeDS.TemplateProcedure = %Paddr(Template); ComposeDS.TrimTemplateLines = RXS_YES; ComposeDS.OmitLineControls = RXS_YES; RXS_StartComposeEngine( ComposeDS ); *INLR = *ON; /end-free P Template B D PI D p Like(RXS_TEMPLATE_PARM) /copy QRPGLETPL,EXAMPLE P E ``` #### Example 3 ```rpgle *-------------------------------------------------------------- * This example code initializes the composition engine for the EXAMPLE template and * configures it with the procedure address for the Template procedure. It also * sets a configuration value to skip composing lines on which there are * uncomposed varaibles. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB /copy QRPGLETPL,EXAMPLE D ComposeDS DS LikeDS(RXS_ComposeDS_t) /free RXS_ResetDS( ComposeDS : RXS_DS_TYPE_COMPOSE ); ComposeDS.TemplateProcedure = %Paddr(Template); ComposeDS.OmitUncomposedLines = RXS_YES; RXS_StartComposeEngine( ComposeDS ); *INLR = *ON; /end-free P Template B D PI D p Like(RXS_TEMPLATE_PARM) /copy QRPGLETPL,EXAMPLE P E ``` #### Example 4 ```rpgle *-------------------------------------------------------------- * This example code initializes the composition engine for the EXAMPLE template and * configures it with an IFS file containing a template file. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB D ComposeDS DS LikeDS(RXS_ComposeDS_t) /free RXS_ResetDS( ComposeDS : RXS_DS_TYPE_COMPOSE ); ComposeDS.Stmf = '/www/RXS/templates/geturi2.tpl'; RXS_StartComposeEngine( ComposeDS ); *INLR = *ON; /end-free ``` ## Data Structures ### RXS_ComposeDS_t ```rpgle D RXS_ComposeDS_t... D DS Qualified Template Inz D ReturnedErrorInfo... D Like(RXS_ReturnedErrorInfoDS_t) Inz // Internal use only D DataStructureType... D 5I 0 Inz(RXS_DS_TYPE_COMPOSE) D OnErrorMessageType... D 5I 0 // Pointer to the address of the subprocedure that will compose the XML or // other character based content. D TemplateProcedure... D * Procptr // IFS location where a log file will be created during composition. D LogFile Like(RXS_Var1Kv_t) // IFS location where a dynamically processed template file is located. If // specified, the TemplateProcedure option is ignored. D Stmf Like(RXS_Var1Kv_t) // Determines whether to append the data to the log file (RXS_YES), or to // overwrite the log file (RXS_NO). Default: RXS_NO D LogFileAppend... D N Inz(RXS_NO) // Determines whether to compose all characters in the CCSID of the Stmf // (RXS_YES), or to use the CCSID of the current job (RXS_NO). // Default: RXS_NO D UseStmfCCSID N // Determines whether to initialize the engine (RXS_YES), or to leave any // previous configuration and composed content in place (RXS_NO). // Default: RXS_YES D Initialize N Inz(RXS_YES) // Determines whether to allow templates up to 256K in length (RXS_YES), or // to use 64K (RXS_NO). // Default: RXS_NO D LargeTemplate... D N Inz(RXS_NO) // Determines whether to strip the line controls from the end of each // template line (RXS_YES), or to leave line controls in place (RXS_NO). // Default: RXS_NO D OmitLineControls... D N Inz(RXS_NO) // Determines whether to trim leading and trailing spaces from the start // and end of each template line (RXS_YES), or to leave all spaces in place // (RXS_NO). Note that spaces are only trimmed from template content and // not from content passed via RXS_ComposeVariable(). // Default: RXS_NO D TrimTemplateLines... D N Inz(RXS_NO) // Determines whether to omit template lines with variables that have not // been composed by RXS_ComposeVariable() (RXS_YES), or to compose all // template lines (RXS_NO). // Default: RXS_NO D OmitUncomposedLines... D N Inz(RXS_NO) ``` --- # RXS_STR() > Converts a numeric value to a trimmed character string. This subprocedure should be used inside an [RXS_Parse()](https://isupport.katointegrations.com/rxs/3.2/rxs_parse.md) parsing subprocedure to convert the parsed data pointer into a character data field. ## Subprocedure Prototype ### IBM i 7.1+ ```rpgle // Returns the character data field extracted from the Pointer parameter. D RXS_STR PR Extproc('RXS_STR') Opdesc D Like(RXS_Var16Mv_t) Rtnparm // Pointer containing character data parsed using an RXS_Parse() parsing // subprocedure. D Pointer * Const // Length of the parsed character data contained in the Pointer parameter. D PointerLen 10I 0 Const ``` ### IBM i 6.1 ```rpgle D RXS_STR PR Extproc('RXS_STR') Opdesc // The character data field extracted from the Pointer parameter. D String Like(RXS_Var16Mv_t) Options(*Varsize) // Pointer containing character data parsed using an RXS_Parse() parsing // subprocedure. D Pointer * Const // Length of the parsed character data contained in the Pointer parameter. D PointerLen 10I 0 Const ``` ## Example Code ### IBM i 7.1+ #### Example 1 ```rpgle *-------------------------------------------------------------- * This example code converts the contents of the pData pointer to character * data and stores it in the field gCelcius. * This process may be used in a RXS_Parse() parsing subprocedure to convert data * retrieved from an XML element to character data for further processing. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB D gCelcius S 5A Varying D pData * Value D pDataLen 10I 0 Value /free gCelsius = RXS_STR( pData : pDataLen ); *INLR = *ON; /end-free ``` ### IBM i 6.1 #### Example 1 ```rpgle *-------------------------------------------------------------- * This example code converts the contents of the pData pointer to character * data and stores it in the field gCelcius. * This process may be used in a RXS_Parse() parsing subprocedure to convert data * retrieved from an XML element to character data for further processing. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB D gCelcius S 5A Varying D pData * Value D pDataLen 10I 0 Value /free RXS_STR( gCelcius : pData : pDataLen ); *INLR = *ON; /end-free ``` --- # RXS_Throw() > Throws an RXS exception with a message and code, to be caught by RXS_Catch(). This subprocedure can be used to throw an error. The error information is populated into a data structure which is then passed to RXS_Throw. The error can be caught by [RXS_Catch()](https://isupport.katointegrations.com/rxs/3.2/rxs_catch.md). ## Subprocedure Prototype ### IBM i 6.1+ ```rpgle D RXS_Throw... D PR Extproc('RXS_Throw') // The RXS_CatchThrowErrorDS_t data structure that contains the error // information to be thrown. D DS Likeds(RXS_CatchThrowErrorDS_t) ``` ## Example Code ### IBM i 6.1+ #### Example 1 ```rpgle *-------------------------------------------------------------- * This example code demonstrates throwing a diagnostic error * by assigning values to a RXS_CatchThrowErrorDS_t datastructure and * throwing the error datastructure to the calling program. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB D gErrorDS DS Likeds(RXS_CatchThrowErrorDS_t) D Inz(*LikeDS) /free // Send a diagnostic error message RXS_ResetDS( gErrorDS : RXS_DS_TYPE_CATCHTHROWERROR ); gErrorDS.MessageId = 'CPF9898'; gErrorDS.MessageFile = 'QCPFMSG'; gErrorDS.MessageData = 'This is a *DIAG error being thrown'; gErrorDS.MessageType = RXS_MESSAGE_TYPE_DIAG; RXS_Throw(gErrorDS); *INLR = *ON; /end-free ``` ## Data Structures ### RXS_CatchThrowErrorDS_t ```rpgle D RXS_CatchThrowErrorDS_t... D DS Qualified Template Inz // The message ID that was received. D MessageId 7A // The message file used to store the message ID. D MessageFile 20A // The message data to be merged with the text of the message ID. D MessageData 1024A Varying D DataStructureType... D 5I 0 Inz(RXS_DS_TYPE_CATCHTHROWERROR) // The type of message that was sent. // Valid values: RXS_MESSAGE_TYPE_DIAG, RXS_MESSAGE_TYPE_COMP, // RXS_MESSAGE_TYPE_INFO, RXS_MESSAGE_TYPE_INQ, RXS_MESSAGE_TYPE_RQS, // RXS_MESSAGE_TYPE_NOTIFY, RXS_MESSAGE_TYPE_ESCAPE, // RXS_MESSAGE_TYPE_STATUS D MessageType 5I 0 // The full message text that combines the value of the message ID's text // and the merged message data. D MessageText 4096A Varying // Set to RXS_YES when you want the error sent to the program that called // the program which is throwing the error. By default, the program // throwing the error will be the target of the error. D ThrowToCaller... D N Inz(RXS_NO) ``` --- # RXS_Transmit() > Performs HTTP/HTTPS requests with configurable headers, authentication, encoding, and timeout options. Performs a HTTP/HTTPS request - allowing you to exchange data with a remote web service. To properly communicate with a web service, you will need to configure the RXS_TransmitDS_t data structure passed in as a parameter. ## Subprocedure Prototype ### V7R1+ ```rpgle // Returns the response data. Note that if RXS_TransmitDS_t.ResponseStmf is // set to an IFS path, the response will be stored there instead. D RXS_Transmit... D PR Extproc('RXS_Transmit') Opdesc D Like(RXS_Var16Mv_t) D Rtnparm // Holds the request data. Note that if RXS_TransmitDS_t.RequestStmf is set // to an IFS path, the request will be read from there instead. D Request Like(RXS_Var16Mv_t) Const D Options(*Omit : *Varsize) // Controls how RXS_Transmit performs the HTTP/HTTPs request. Uses // RXS_TransmitDS_t as a template. D DS LikeDS(RXS_TransmitDS_t) ``` ### V6R1 ```rpgle D RXS_Transmit... D PR Extproc('RXS_Transmit') Opdesc // Holds the response data. Note that if RXS_TransmitDS_t.ResponseStmf is // set to an IFS path, the response will be stored there instead. D Response Like(RXS_Var16Mv_t) D Options(*Omit : *Varsize) // Holds the request data. Note that if RXS_TransmitDS_t.RequestStmf is set // to an IFS path, the request will be read from there instead. D Request Like(RXS_Var16Mv_t) Const D Options(*Omit : *Varsize) // Controls how RXS_Transmit performs the HTTP/HTTPs request. Uses // RXS_TransmitDS_t as a template. D DS LikeDS(RXS_TransmitDS_t) ``` ## Example Code ### IBM i 7.1+ #### HTTP GET ```rpgle *-------------------------------------------------------------- * This example performs a simple HTTP GET operation against the URL example.com and stores the retrieved response data in the field Response. * Because this is a HTTP GET, we don't need to pass a Request parameter. * During the execution of RXS_Transmit(), the API will create a log file at '/tmp/rxs_transmit1_log.txt' *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB D TransmitDS DS LikeDS(RXS_TransmitDS_t) D Inz(*LikeDS) D Response S Like(RXS_Var64Kv_t) /free RXS_ResetDS( TransmitDS : RXS_DS_TYPE_TRANSMIT ); TransmitDS.URI = 'https://example.com/'; TransmitDS.HTTPMethod = RXS_HTTP_METHOD_GET; TransmitDS.LogFile = '/tmp/rxs_transmit1_log.txt'; Response = RXS_Transmit( *Omit : TransmitDS ); *INLR = *ON; /end-free ``` #### HTTP POST ```rpgle *-------------------------------------------------------------- * This example performs a HTTP POST against a public web service that provides conversion between Fahrenheit and Celsius. * This is a HTTP POST, so we need to provide a Request parameter. * Because this is using SOAP, we need to specify Content-type and SOAPAction headers. * Lastly, this example uses RXS_JobLog() to write the full response XML to the job log. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB D TransmitDS DS LikeDS(RXS_TransmitDS_t) D Inz(*LikeDS) D Request S Like(RXS_Var64Kv_t) D Response S Like(RXS_Var64Kv_t) /free Request = '' + '' + ''+ '100' + ''; RXS_ResetDS( TransmitDS : RXS_DS_TYPE_TRANSMIT ); TransmitDS.URI = 'http://www.w3schools.com/webservices/tempconvert.asmx'; TransmitDS.HTTPMethod = RXS_HTTP_METHOD_POST; TransmitDS.LogFile = '/tmp/rxs_transmit2_log.txt'; TransmitDS.HeaderContentType = 'text/xml; charset=utf-8'; TransmitDS.HeaderSOAPAction = '"http://www.w3schools.com/webservices/FahrenheitToCelsius"'; Response = RXS_Transmit( Request : TransmitDS ); RXS_JobLog( Response ); *INLR = *ON; /end-free ``` #### HTTP Custom Headers ```rpgle *-------------------------------------------------------------- * This example demonstrates how to set custom HTTP headers with RXS_Transmit(). * You may specify up to 50 custom HTTP headers sent with a request. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB D TransmitDS DS LikeDS(RXS_TransmitDS_t) D Inz(*LikeDS) D Response S Like(RXS_Var64Kv_t) /free RXS_ResetDS( TransmitDS : RXS_DS_TYPE_TRANSMIT ); TransmitDS.URI = 'https://example.com/'; // Set a custom HTTP header that looks like this: // X-API-Token: [your-api-token] TransmitDS.CustomHeaderName(1) = 'X-API-Token'; TransmitDS.CustomHeaderValue(1) = '[your-api-token]'; // Set a custom HTTP header that looks like this: // ExampleHeader: hello world TransmitDS.CustomHeaderName(2) = 'ExampleHeader'; TransmitDS.CustomHeaderValue(2) = 'hello world'; Response = RXS_Transmit( *Omit : TransmitDS ); *INLR = *ON; /end-free ``` #### HTTP Basic Authentication ```rpgle *-------------------------------------------------------------- * This example demonstrates how to specify a username and * password for HTTP Basic Authentication with RXS_Transmit(). *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB D TransmitDS DS LikeDS(RXS_TransmitDS_t) D Inz(*LikeDS) D Response S Like(RXS_Var64Kv_t) /free RXS_ResetDS( TransmitDS : RXS_DS_TYPE_TRANSMIT ); TransmitDS.URI = 'https://example.com/'; TransmitDS.BasicAuthUser = 'username'; TransmitDS.BasicAuthPassword = 'password'; Response = RXS_Transmit( *Omit : TransmitDS ); *INLR = *ON; /end-free ``` #### HTTP Bearer Authentication ```rpgle *-------------------------------------------------------------- * This examples showcases using RXS_Transmit to set an Authorization header. * When using CustomHeaderName and CustomHeaderValue arrays with RXS_Transmit() * to set an Authorization header, the Bearer portion needs to go in the Value * field, followed by a space before the API key is concatenated to the Value field. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB D TransmitDS DS LikeDS(RXS_TransmitDS_t) D Inz(*LikeDS) D Response S Like(RXS_Var64Kv_t) /free RXS_ResetDS( TransmitDS : RXS_DS_TYPE_TRANSMIT ); TransmitDS.URI = 'https://example.com/'; TransmitDS.CustomHeaderName(1) = 'Authorization'; TransmitDS.CustomHeaderValue(1) = 'Bearer ' + '[your-api-token]'; Response = RXS_Transmit( *Omit : TransmitDS ); *INLR = *ON; /end-free ``` #### HTTP Cookie Header Data ```rpgle *-------------------------------------------------------------- * This example showcases sending cookie data. However, instead of * reading the data from a file, you may specify it by utilizing * HeaderCookieData. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB D TransmitDS DS LikeDS(RXS_TransmitDS_t) D Inz(*LikeDS) D Response S Like(RXS_Var64Kv_t) /free RXS_ResetDS( TransmitDS : RXS_DS_TYPE_TRANSMIT ); TransmitDS.URI = 'example.com'; TransmitDS.HeaderCookieData = 'your cookie data'; Response = RXS_Transmit( *Omit : TransmitDS ); *INLR = *ON; /end-free ``` #### HTTP Cookie Header File ```rpgle *-------------------------------------------------------------- * This example showcases sending cookie data, utilizing an IFS * file which contains said data. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB D TransmitDS DS LikeDS(RXS_TransmitDS_t) D Inz(*LikeDS) D Response S Like(RXS_Var64Kv_t) /free RXS_ResetDS( TransmitDS : RXS_DS_TYPE_TRANSMIT ); TransmitDS.URI = 'example.com'; TransmitDS.HeaderCookieFiles(1) = '/tmp/cookie.txt'; Response = RXS_Transmit( *Omit : TransmitDS ); *INLR = *ON; /end-free ``` ### IBM i 6.1 #### HTTP GET ```rpgle *-------------------------------------------------------------- * This example performs a simple HTTP GET operation against the URL example.com and stores the retrieved response data in the field Response. * Because this is a HTTP GET, we don't need to pass a Request parameter. * During the execution of RXS_Transmit(), the API will create a log file at '/tmp/rxs_transmit1_log.txt' * Note that the compiler directive RXSV6R1 is defined. This ensures that if you upgrade your 6.1 system * to 7.1 at a later date that you will not need to make changes to this program to be able to compile * it again due to the structural differences between how RXS APIs function on 6.1 vs 7.1 / 7.2 *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /define RXSV6R1 /copy QRPGLECPY,RXSCB D TransmitDS DS LikeDS(RXS_TransmitDS_t) D Inz(*LikeDS) D Response S Like(RXS_Var64Kv_t) /free RXS_ResetDS( TransmitDS : RXS_DS_TYPE_TRANSMIT ); TransmitDS.URI = 'https://example.com/'; TransmitDS.HTTPMethod = RXS_HTTP_METHOD_GET; TransmitDS.LogFile = '/tmp/rxs_transmit1_log.txt'; RXS_Transmit( Response : *Omit : TransmitDS ); *INLR = *ON; /end-free ``` #### HTTP POST ```rpgle *-------------------------------------------------------------- * This example performs a HTTP POST against a public web service that provides conversion between Fahrenheit and Celsius. * This is a HTTP POST, so we need to provide a Request parameter. * Because this is using SOAP, we need to specify Content-type and SOAPAction headers. * Lastly, this example uses RXS_JobLog() to write the full response XML to the job log. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /define RXSV6R1 /copy QRPGLECPY,RXSCB D TransmitDS DS LikeDS(RXS_TransmitDS_t) D Inz(*LikeDS) D Request S Like(RXS_Var64Kv_t) D Response S Like(RXS_Var64Kv_t) /free Request = '' + '' + ''+ '100' + ''; RXS_ResetDS( TransmitDS : RXS_DS_TYPE_TRANSMIT ); TransmitDS.URI = 'http://www.w3schools.com/webservices/tempconvert.asmx'; TransmitDS.HTTPMethod = RXS_HTTP_METHOD_POST; TransmitDS.LogFile = '/tmp/rxs_transmit2_log.txt'; TransmitDS.HeaderContentType = 'text/xml; charset=utf-8'; TransmitDS.HeaderSOAPAction = '"http://www.w3schools.com/webservices/FahrenheitToCelsius"'; RXS_Transmit( Response : Request : TransmitDS ); RXS_JobLog( Response ); *INLR = *ON; /end-free ``` #### HTTP Custom Headers ```rpgle *-------------------------------------------------------------- * This example demonstrates how to set custom HTTP headers with RXS_Transmit(). * You may specify up to 50 custom HTTP headers sent with a request. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /define RXSV6R1 /copy QRPGLECPY,RXSCB D TransmitDS DS LikeDS(RXS_TransmitDS_t) D Inz(*LikeDS) D Response S Like(RXS_Var64Kv_t) /free RXS_ResetDS( TransmitDS : RXS_DS_TYPE_TRANSMIT ); TransmitDS.URI = 'https://example.com/'; // Set a custom HTTP header that looks like this: // X-API-Token: [your-api-token] TransmitDS.CustomHeaderName(1) = 'X-API-Token'; TransmitDS.CustomHeaderValue(1) = '[your-api-token]'; // Set a custom HTTP header that looks like this: // ExampleHeader: hello world TransmitDS.CustomHeaderName(2) = 'ExampleHeader'; TransmitDS.CustomHeaderValue(2) = 'hello world'; RXS_Transmit( Response : *Omit : TransmitDS ); *INLR = *ON; /end-free ``` #### HTTP Basic Authentication ```rpgle *-------------------------------------------------------------- * This example demonstrates how to specify a username and * password for HTTP Basic Authentication with RXS_Transmit(). *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /define RXSV6R1 /copy QRPGLECPY,RXSCB D TransmitDS DS LikeDS(RXS_TransmitDS_t) D Inz(*LikeDS) D Response S Like(RXS_Var64Kv_t) /free RXS_ResetDS( TransmitDS : RXS_DS_TYPE_TRANSMIT ); TransmitDS.URI = 'https://example.com/'; TransmitDS.BasicAuthUser = 'username'; TransmitDS.BasicAuthPassword = 'password'; RXS_Transmit( Response : *Omit : TransmitDS ); *INLR = *ON; /end-free ``` #### HTTP Bearer Authentication ```rpgle *-------------------------------------------------------------- * This examples showcases using RXS_Transmit to set an Authorization header. * When using CustomHeaderName and CustomHeaderValue arrays with RXS_Transmit() * to set an Authorization header, the Bearer portion needs to go in the Value * field, followed by a space before the API key is concatenated to the Value field. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /define RXSV6R1 /copy QRPGLECPY,RXSCB D TransmitDS DS LikeDS(RXS_TransmitDS_t) D Inz(*LikeDS) D Response S Like(RXS_Var64Kv_t) /free RXS_ResetDS( TransmitDS : RXS_DS_TYPE_TRANSMIT ); TransmitDS.URI = 'https://example.com/'; TransmitDS.CustomHeaderName(1) = 'Authorization'; TransmitDS.CustomHeaderValue(1) = 'Bearer ' + '[your-api-token]'; RXS_Transmit( Response : *Omit : TransmitDS ); *INLR = *ON; /end-free ``` #### HTTP Cookie Header Data ```rpgle *-------------------------------------------------------------- * This example showcases sending cookie data. However, instead of * reading the data from a file, you may specify it by utilizing * HeaderCookieData. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /define RXSV6R1 /copy QRPGLECPY,RXSCB D TransmitDS DS LikeDS(RXS_TransmitDS_t) D Inz(*LikeDS) D Response S Like(RXS_Var64Kv_t) /free RXS_ResetDS( TransmitDS : RXS_DS_TYPE_TRANSMIT ); TransmitDS.URI = 'example.com'; TransmitDS.HeaderCookieData = 'your cookie data'; RXS_Transmit( Response : *Omit : TransmitDS ); *INLR = *ON; /end-free ``` #### HTTP Cookie Header File ```rpgle *-------------------------------------------------------------- * This example showcases sending cookie data, utilizing an IFS * file which contains said data. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /define RXSV6R1 /copy QRPGLECPY,RXSCB D TransmitDS DS LikeDS(RXS_TransmitDS_t) D Inz(*LikeDS) D Response S Like(RXS_Var64Kv_t) /free RXS_ResetDS( TransmitDS : RXS_DS_TYPE_TRANSMIT ); TransmitDS.URI = 'https://example.com/'; TransmitDS.HeaderCookieFiles(1) = '/tmp/cookie.txt'; RXS_Transmit( Response : *Omit : TransmitDS ); *INLR = *ON; /end-free ``` ## Data Structures ### RXS_TransmitDS_t ```rpgle D RXS_TransmitDS_t... D DS Qualified Template Inz D ReturnedErrorInfo... D LikeDS(RXS_ReturnedErrorInfoDS_t) Inz D OnErrorMessageType... D 10I 0 // Specify the full URI used for the request. If a non-standard port (e.g. // other than 80 for an HTTP request, and 443 for an HTTPS request) is // needed, this must be specified in the request. // Example: https://testuri.org:9001/webservice D URI Like(RXS_Var8Kv_t) // An IFS path can be specified in this subfield - if it is, it will be // used as the request data instead of the value of the pRequest parm. D RequestStmf Like(RXS_Var1Kv_t) // Specify the CCSID that the request data will be converted into, and the // response data will be converted from. // Default: RXS_CCSID_ISO88591 D RequestCcsid 10I 0 Inz(RXS_CCSID_ISO88591) // An IFS path can be specified in this subfield - if it is, any output of // the RXS_Transmit operation will be stored in the specified IFS file. D ResponseStmf Like(RXS_Var1Kv_t) // If the response is being stored in an IFS file (determined by whether or // not the ResponseStmf subfield is occupied), the response data will be // converted to this CCSID. // Default: RXS_CCSID_UTF8 D ResponseStmfCcsid... D 10I 0 Inz(RXS_CCSID_UTF8) // Specify a value in seconds for a timeout on the request. // Default: 60 D Timeout 10U 0 Inz(60) // Determines the HTTP request method used. // Valid values: RXS_HTTP_METHOD_GET, RXS_HTTP_METHOD_POST, // RXS_HTTP_METHOD_PUT, RXS_HTTP_METHOD_DELETE, RXS_HTTP_METHOD_PATCH, // RXS_HTTP_METHOD_HEAD, RXS_HTTP_METHOD_OPTIONS // Default: RXS_HTTP_METHOD_POST D HTTPMethod 3I 0 Inz(RXS_HTTP_METHOD_POST) // An IFS path can be specified to log the request & response, as well as // additional HTTP request debugging information. This option is disabled // by default, and should not be left enabled in production environments // due to increased execution time and privacy concerns. D LogFile Like(RXS_Var1Kv_t) // Specify a value in seconds to cause a timeout during an SSL handshake. // Default: 300 D SSLTimeout 10U 0 Inz(300) // Used to assign an application ID for RXS_Transmit. D SSLApplicationID... D Like(RXS_Var1Kv_t) // If a SSL certificate store other than the *SYSTEM store should be used, // the IFS path can be specified here. D SSLCertStore... D Like(RXS_Var1Kv_t) // If using a non-*SYSTEM SSL certificate store, the password can be // specified here. D SSLCertStorePassword... D Like(RXS_Var1Kv_t) // This option determines whether RXS_Transmit verifies the authenticity of // the peer's certificate. Setting this to RXS_NO this in a production // capacity is strongly discouraged. // Valid values: RXS_YES, RXS_NO // Default: RXS_YES D SSLVerifyPeer... D N Inz(RXS_YES) // This option determines whether RXS_Transmit verifies that the server // certificate is for the server it is known as. Setting this to RXS_NO // this in a production capacity is strongly discouraged. // Valid values: RXS_YES, RXS_NO // Default: RXS_YES D SSLVerifyHost... D N Inz(RXS_YES) // Specify the HTTP protocol version being used. // Valid values: RXS_HTTP_VERSION_ANY, RXS_HTTP_VERSION_11, // RXS_HTTP_VERSION_10 // Default: RXS_HTTP_VERSION_ANY D HTTPVersion 4P 2 Inz(RXS_HTTP_VERSION_ANY) // Specify the user ID for this parameter if Basic Authentication is used // on this request. D BasicAuthUser... D Like(RXS_Var1Kv_t) // Specify the password for this parameter if Basic Authentication is used // on this request. D BasicAuthPassword... D Like(RXS_Var1Kv_t) // Specifies the URI used as a proxy for the request. D ProxyURI Like(RXS_Var1Kv_t) // If using a proxy on this request that requires a user id and password, // specify the proxy user id in this subfield. D ProxyUser... D Like(RXS_Var1Kv_t) // If using a proxy on this request that requires a user id and password, // specify the proxy password in this subfield. D ProxyPassword... D Like(RXS_Var1Kv_t) // Specifies if HTTP headers should be sent with the request. RXS_YES will // tell RXS_Transmit that all HTTP headers as well as the user defined // headers are sent with the request. RXS_NO will tell RXS_Transmit that no // HTTP headers are sent with the request - only the request data is sent. // Valid values: RXS_YES, RXS_NO // Default: RXS_YES D SendHTTPHeaders... D N Inz(RXS_YES) // Specify any cookie data to be sent with this request. Further // instructions for formatting this data is available at RFC2109. D HeaderCookieData... D Like(RXS_Var8Kv_t) // Up to 50 paths to IFS files may be specified which contain cookie data. // Further instructions for formatting this data is available at RFC2109. D HeaderCookieFiles... D Like(RXS_Var1Kv_t) Dim(50) // If calling a SOAP web service, the SOAPAction HTTP header field is // generally required. This is typically surrounded by double quotes. // Example: "http://electrocommerce.org/abc#MyMessage" D HeaderSOAPAction... D Like(RXS_Var1Kv_t) // Some web applications may function differently depending upon the user // agent specified. // Default: KrengelTech HTTP Client D HeaderUserAgent... D Like(RXS_Var1Kv_t) D Inz('KrengelTech HTTP Client') D HeaderAccept Like(RXS_Var1Kv_t) D HeaderHost Like(RXS_Var1Kv_t) D HeaderReferer... D Like(RXS_Var1Kv_t) D HeaderConnection... D Like(RXS_Var1Kv_t) // The MIME type of the body of the request (used with POST requests). // Default: text/xml D HeaderContentType... D Like(RXS_Var1Kv_t) // Specifies the name of up to 50 custom HTTP headers sent with the // request. D CustomHeaderName... D 64A Varying Dim(50) // Specifies the value of up to 50 custom HTTP headers sent with the // request. D CustomHeaderValue... D Like(RXS_Var1Kv_t) Dim(50) // Data structure using RXS_HTTPResponseDS_t as a template. Populated by // RXS_Transmit at the end of the request. D HTTPResponse LikeDS(RXS_HTTPResponseDS_t) D Inz(*LikeDS) // Internal use only D InputPointer... D * // Internal use only D InputLength 10I 0 // Internal use only D OutputPointer... D * // Internal use only D OutputLength 10I 0 // Internal use only D Reserved 4096A D InputCCSID 10I 0 Inz(RXS_CCSID_JOB) D OutputCCSID 10I 0 Inz(RXS_CCSID_JOB) D LogFileCCSID 10I 0 Inz(RXS_CCSID_UTF8) D LogFileAppend... D N Inz(RXS_NO) D LogHandler... D * Procptr D LogHandlerData... D * D LogHandlerDataLength... D 10I 0 D EnableExpectHeader... D N Inz(RXS_NO) // Specify the IP address and optionally the port of the desired interface // to bind to when transmiting to the remote server. When specify port, it // will be separated from the IP with a colon: IP:Port D LocalInterface... D 64A Varying ``` --- # RXS_Validate() > Validates an XML document against an XSD schema, returning validation errors if the document does not conform. This subprocedure performs validation options on a given character string. Currently it can perform XSD validation against XML. ## Subprocedure Prototype ### IBM i 6.1+ ```rpgle D RXS_Validate... D PR N Extproc('RXS_Validate') Opdesc // Character data to be validated. D pData Like(RXS_Var16Mv_t) D Options(*Omit: *Varsize) Const // This field can contain either an RXS_XsdValidationDS_t data structure, // or the XSD stored in a character field. D pDS Like(RXS_Var64K_t) D Options(*Varsize) ``` ## Example Code ### IBM i 6.1+ #### Example 1 ```rpgle *-------------------------------------------------------------- * This example code validates XML data against a specified XSD. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB D XsdValidateDS... D DS LikeDS(RXS_XsdValidationDS_t) D Inz(*LikeDS) D goodXml S Like(RXS_Var64Kv_t) /free // This example assumes that goodXml contains XML data. // This data could be retrieved from RXS_GetStdIn(), or composed // using the RXS composition engine. RXS_ResetDS( XsdValidateDS : RXS_DS_TYPE_XSDVALIDATION ); XsdValidateDS.XsdLocation = 'http://files.rpg-xml.com/example/xsdvalidate/validate.xsd'; if RXS_Validate( goodXml : XsdValidateDS ); RXS_JobLog( 'XML 1 Validated successfully'); else; RXS_JobLog( 'XML 1 Validation failed'); RXS_JobLog( 'Validation Error #%s: %s' : %Char( XsdValidateDS.ValidationErrorCode ) : XsdValidateDS.ValidationErrorText ); endif; *INLR = *ON; /end-free ``` ## Data Structures ### RXS_XsdValidationDS_t ```rpgle D RXS_XsdValidationDS_t... D DS Qualified Template Inz D ReturnedErrorInfo... D LikeDS(RXS_ReturnedErrorInfoDS_t) Inz D OnErrorMessageType... D 10I 0 // The IFS path or URI where the XSD is located. D XsdLocation... D Like(RXS_Var1Kv_t) // Error code returned by the validation operation. D ValidationErrorCode... D 10I 0 // Error message returned by the validation operation. D ValidationErrorText... D Like(RXS_Var1Kv_t) // CCSID of the XSD data. D XsdCcsid 10I 0 // Internal use only D XsdPointer * // Internal use only D XsdLength 10I 0 // The CCSID of the XML data. D XmlCcsid 10I 0 // Internal use only D XmlPointer * // Internal use only D XmlLength 10I 0 // Internal use only D Reserved 4096A ``` --- # RXS_XPath() > Evaluates an XPath expression against a DOM and returns the matching node value as a string. This subprocedure assists with building an XPath string. This is recommended over simply manually building an XPath string. In addition to providing an easy way to include numeric replacement values, it also allows for including a wildcard namespace. The wildcard namespace syntax is translated to its' XPath 1.0 equivalent and returned along with any replacements that were passed. ## Subprocedure Prototype ### IBM i 6.1+ ```rpgle // Returns the constructed XPath string. D RXS_XPath... D PR Extproc('RXS_XPath') Opdesc D Like(RXS_Var8Kv_t) D Rtnparm // Holds the initial XPath string template D pXPath Like(RXS_Var8Kv_t) Const D Options(*Varsize) // Holds a numeric replacement value. Replaces the first unreplaced %u // found in the XPath string template. D pReplacement1 10U 0 Value Options(*Nopass) // Holds a numeric replacement value. Replaces the first unreplaced %u // found in the XPath string template. D pReplacement2 10U 0 Value Options(*Nopass) // Holds a numeric replacement value. Replaces the first unreplaced %u // found in the XPath string template. D pReplacement3 10U 0 Value Options(*Nopass) // Holds a numeric replacement value. Replaces the first unreplaced %u // found in the XPath string template. D pReplacement4 10U 0 Value Options(*Nopass) // Holds a numeric replacement value. Replaces the first unreplaced %u // found in the XPath string template. D pReplacement5 10U 0 Value Options(*Nopass) // Holds a numeric replacement value. Replaces the first unreplaced %u // found in the XPath string template. D pReplacement6 10U 0 Value Options(*Nopass) // Holds a numeric replacement value. Replaces the first unreplaced %u // found in the XPath string template. D pReplacement7 10U 0 Value Options(*Nopass) // Holds a numeric replacement value. Replaces the first unreplaced %u // found in the XPath string template. D pReplacement8 10U 0 Value Options(*Nopass) // Holds a numeric replacement value. Replaces the first unreplaced %u // found in the XPath string template. D pReplacement9 10U 0 Value Options(*Nopass) // Holds a numeric replacement value. Replaces the first unreplaced %u // found in the XPath string template. D pReplacement10... D 10U 0 Value Options(*Nopass) ``` ## Example Code ### IBM i 6.1+ #### Example 1 ```rpgle *-------------------------------------------------------------- * This example code demonstrates creating an XPath that can be used for * further processing. *-------------------------------------------------------------- H DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB D gXPath S Like(RXS_Var1Kv_t) /free gXPath = RXS_XPath( '/*:bookstore/*:book' ); *INLR = *ON; /end-free ``` --- # Apply License (APYLIC) > Applies a permanent or temporary license key to the RPG API Express installation. To apply a permanent or temporary license key, you will use the included command APYLIC. Your license key will typically be supplied via email in a command string: `APYLIC LICKEY(6E2222898982C8F1380F4DF08A23922C) PRODUCT(RXS)` Or, you can copy and paste the received key into the command: ![Apply License (APYLIC)](https://isupport.katointegrations.com/llms/rpg-api-express-3.2/apylic.png "Apply License (APYLIC)") In either case after running the APYLIC command, you should receive a message that says **License applied successfully** If you don't receive that message or receive an error message, please contact us at isupport@katointegrations.com. --- # Display License (DSPLIC) > Legacy alias for DSPMCHINF; displays machine and license information needed for activation key generation. DSPLIC is used to retrieve system information as well as license status. **Note:** [Display Machine Info (DSPMCHINF)](https://isupport.katointegrations.com/rxs/3.2/dspmchinf.md) is an alias for this command. These commands may be used interchangeably. The command does not have any parameters: `DSPLIC` The command should display a screen similar to the one below. This screen indicates all the information necessary to generate your license key, as well as the current status of any applied license keys. ![Display License (DSPLIC)](https://isupport.katointegrations.com/llms/rpg-api-express-3.2/dsplic.png "Display License (DSPLIC)") If you don't receive that message or receive an error message, please contact us at isupport@katointegrations.com. --- # Display Machine Info (DSPMCHINF) > Displays system machine information and license key status required by support to generate activation keys. DSPMCHINF is used to retrieve system information as well as license status. **Note:** DSPMCHINF is an alias for the [Display License (DSPLIC)](https://isupport.katointegrations.com/rxs/3.2/dsplic.md) command. These commands may be used interchangeably. The command does not have any parameters: `DSPMCHINF` The command should display a screen similar to the one below. This screen indicates all the information necessary to generate your license key, as well as the current status of any applied license keys. ![Display Machine Info (DSPMCHINF)](https://isupport.katointegrations.com/llms/rpg-api-express-3.2/dspmchinf.png "Display Machine Info (DSPMCHINF)") If you don't receive that message or receive an error message, please contact us at isupport@katointegrations.com. --- # Display Version (DSPVER) > Displays the currently installed version of RPG API Express. DSPVER can be used to retrieve the version number of the currently installed product. The command does not have any parameters: `DSPVER` You should receive a message indicating the currently installed version as well as the library in which the product is installed. ![Display Version (DSPVER)](https://isupport.katointegrations.com/llms/rpg-api-express-3.2/dspver.png "Display Version (DSPVER)") If you don't receive that message or receive an error message, please contact us at isupport@katointegrations.com. --- # RXSMENU > Menu interface for viewing RXS installation details and managing product license keys. The RXSMENU menu can be used to retrieve information about your RPG-XML Suite installation, or to work with your product license keys. ![RXSMENU](https://isupport.katointegrations.com/llms/rpg-api-express-3.2/rxsmenu.png) --- # Create RXS Server (CRTRXSSVR) > Creates an Apache HTTP server instance configured for use with RPG API Express. The Create RXS HTTP Server (CRTRXSSVR) command allows the user to create an HTTP server instance for use by RPG-XML Suite. ## Parameters ### HTTP server instance (HTTPSVR) This is a required parameter. Specifies the name of the HTTP server instance to create. If this parameter is specified with any value other than HTTPSVR(*RXSLIB), an RPG-XML Suite development library is also created, with the same name as the HTTP server instance. Several objects are copied into it from the RPG-XML Suite product library. It is these objects (files, programs service programs, etc.) that are used when you develop your applications which use RPG-XML Suite. If you specify HTTPSVR(*RXSLIB), only the HTTP server instance is created with the same name as the RPG-XML Suite product library. You should use this option if you only wish to use the RXS Router product, and are not intending to do any other RPG-XML Suite development. #### Possible Values: `name` : An HTTP server instance is created and an RPG-XML Suite development environment library is also created with the same name. `RXSLIB` : An HTTP server instance is created with the same name as the RPG-XML Suite product library. No RPG-XML Suite development environment library is created. ### RXS product library (RXSLIB) Specifies the name of the RPG-XML Suite product library to use when creating the RPG-XML Suite environment. #### Possible Values: `RXS` : The default RPG-XML Suite product library RXS will be used. `library-name` : The named RPG-XML Suite product library will be used. ### Port number (PORT) Specifies the port number to use for the HTTP server instance. **Note: No checks are performed that the specified port number is not already in use, either by an existing HTTP server instance or by another application.** #### Possible Values: `DFT` : The default port number 8181 is used. `port-number` : The specified port number is used. --- # Process HTTP Server Instance (HTTP) > Manages Apache HTTP server instances with options to start, end, restart, view logs, inspect configuration, and manage autostart. The barebones approach to ending an Apache HTTP server is to use the ENDTCPSVR command. The ENDTCPSVR command has a default of *ALL for the SERVER parameter which can obviously shut down all TCP related services, making you very unpopular. For this reason we have created a command that can help you with your Apache HTTP server needs. The command is named "HTTP". Simply type HTTP on the command line and select F4 to see the various options. ## Parameters ### HTTP Server Instance (HTTPSVR) Specify the Apache HTTP server instance to perform actions upon. #### Possible Values: `*ALL` : Work with all HTTP instances. The only valid values for the Option parameter that can be used with this is *WRK. `*ADMIN` : Work with all *ADMIN HTTP instances. The only valid values for the Option parameter that can be used with this are *WRK, *START, *RESTART, and *END `name` : Specify the name of a specific HTTP instance to work with. All values are valid for the Option parameter. `generic-name` : Specify the generic name of the HTTP server instance to be processed. A generic name is a character string that contains one or more characters followed by an asterisk (*). All values are valid for the Option parameter. ### Option (OPTION) Specify the operation which should be performed on the specified HTTP server instance(s). #### Possible Values: `*WRK` : Works with the specified HTTP server instance(s). This displays the Work with Active Jobs (WRKACTJOB) screen, subsetted to show only the selected HTTP server instance(s). `*START` : Starts the specified HTTP server instance. `*END` : Ends the specified HTTP server instance. `*INZRTR` : Intializes the RXSRTR cache. `*RESTART` : Restarts the specified HTTP server instance. `*CONF` : Edits the configuration file for the specified HTTP server instance. If the user does not have sufficient authority to edit the configuration file, it will be displayed. `*LOGS` : Displays a list of the the error logs for the specified HTTP server instance. `*CURLOG` : Displays the current day's error log for the specified HTTP server instance. `*DOCS` : Displays the contents of the '/htdocs/' folder for the specified HTTP server instance. `*DIR` : Displays the entire directory structure for the specified HTTP server instance. --- # RXS Router (RXSRTR) > CGI routing program that dispatches HTTP requests to RPG programs, supporting library lists, user profile swapping, audit logging, and ASP group selection. The RXS Router (RXSRTR) is a program included since RPG-XML Suite v2.10+ that runs on the IBM i behind the Apache HTTP server, acting as a 'router' for CGI requests which use the HTTP protocol. RXSRTR enables you to both simplify your HTTP processing and add functionality which is not directly available through the HTTP server configuration. Once installed, RXSRTR sits seamlessly between your HTTP server and your CGI programs; no changes are required to existing CGI program functionality and no changes are required to any existing URLs you use to access your CGI programs (such as user favorites or links from webpages). RXSRTR enables you to perform the following additional functionality: - Route all CGI requests through a single URL format - Specify a library list to use when calling programs - Swap to a different user profile when calling programs - Log all information about the request to an audit log file - Call non-CGI programs, passing parameters and receiving responses - Specify an activation group allowing files to remain open between calls, while maintaining separation between environments - Specify product libraries which will be placed ahead of libraries in the user library list All this functionality is data-driven - that is, it is controlled via data held in a single control file used by RXSRTR. If you need to add or change the programs you need to call, you simply update the RXSRTR control file. ## HTTP Configuration Without RXSRTR Below is an example HTTP server instance configuration fragment, showing how three different URL formats match different CGI program calls in different libraries: ```apache ScriptAliasMatch ^/cgi-bin/(.*) /qsys.lib/public.lib/$1.pgm ScriptAliasMatch ^/cust/(.*) /qsys.lib/customers.lib/initial.pgm ScriptAliasMatch ^/db2wse/(.*) /qsys.lib/db2wse.lib/db2wse.pgm Options +ExecCGI Allow From all Options +ExecCGI Allow From all Options +ExecCGI Allow From all ``` In this case, multiple ScriptAliasMatch directives route different URLs to different CGI programs in different libraries. For instance, assuming this HTTP server is on a IBM i with an IP address of 192.168.0.1, below is a list of example URLs and the resulting program which will be called: | URL used | CGI Program Called | |----------|---| | `http://192.168.0.1/cgi-bin/mypgm` | PUBLIC/MYPGM | | `http://192.168.0.1/cgi-bin/yourpgm` | PUBLIC/MYPGM | | `http://192.168.0.1/cust/john` | CUSTOMERS/INITIAL | | `http://192.168.0.1/cust/` | CUSTOMERS/INITIAL | | `http://192.168.0.1/db2wse/string` | DB2WSE/DB2WSE | This can be confusing, since it's not always clear which program will eventually be called when a given URL is used and the configuration can grow very large and complex, since each library specified has to have its own section in the configuration, specifying authorities etc. Additionally, if any changes are required, the HTTP server must be restarted. Finally, the above configuration is also insecure, since it allows any user to call any program in the PUBLIC library. ## HTTP Configuration With RXSRTR By contrast, RXSRTR allows you to replace all the above configuration with a single ScriptAliasMatch and section in your HTTP server instance configuration file which can be used for all CGI program calls: ```apache ScriptAliasMatch ^/(([^/.]+/)*[^/.]+)$ /qsys.lib/RXS.lib/rxsrtr.pgm Options +ExecCGI Allow From all ``` Using the above directive, every URL will call RXSRTR and by configuring RXSRTR, you can ensure that all existing URLs (which may exist as links in web pages, user's bookmarks etc.) will result in the same programs being called as before. Within the RXSRTR configuration itself, you define which programs should be called and how. You can dynamically change these configuration settings without needing to change the HTTP server configuration or restart the HTTP server. This means that you can have a much simpler HTTP configuration. Because RXSRTR works at the program level, you can easily configure RXSRTR to specify exactly which programs can be called, immediately making your system more secure. When a request is matched by the HTTP server which results in RXSRTR being called, RXSRTR analyzes the URL to determine a 'request routing identifier' (RRID), which will be used to determine the routing call processing for the request. This processing is described in detail in the [RXS Router Configuration](#rxs-router-configuration) section. Once the RRID has been determined for a request, RXSRTR retrieves the control data for that RRID. The control data specifies not only the actual program to call, but also the following characteristics of the call: - Which additional libraries to add to the library list prior to calling the program - Which user profile to swap to for the call RXSRTR control data is held in the RXSRTRCTL file. Each record has a key of the RRID and contains a 'routing data' field. Within the routing data field, various flag/value pairs can be specified to control what program will be called for the given RRID. The format of the DATA field is as follows: `{-flag value -flag value -flag value...}` where flag can be one of a number of special values as follows: | Flag | Description of associated value | |------|---| | `pgm` | Name of application program to be called **(required)** | | `lib` | Name of application library | | `usrprf` | User profile to run as | | `passwd` | Password for user profile | | `liblst` | Comma-separated library list (10 libraries max) or qualified job description name | | `cvtopt` | Comma-separated conversion options | | `response` | Response type for non-CGI programs | | `actgrp` | Activation group | | `prdlib` | Product library | Note the following specifications related to control data flags and the way they must be specified in the DATA field in the RXSRTRCTL file: - Each flag must be prefixed with a minus-sign, e.g. -pgm - Values are automatically converted to upper-case for processing - Flag/value pairs can be specified in any order - Except for the pgm flag, all flag/value pairs are optional - Comma-separated lists (for the liblst and cvtopt flags) must contain no embedded blanks Note that there is a special *CONFIG record shipped in the RXS router control file which contains different valid flag values. See [RXS Router Configuration](#rxs-router-configuration) for more details. ## Control Flag Details ### pgm The **pgm** flag defines the program to be called. It can either be a valid i5/OS name or a special value. Valid special values are \*0-\*9. If a special value is used, the corresponding SCRIPT_NAME path segment is used as the program name, where 0 is the RRID itself, 1 is the next segment and so on. For instance, if RXSRTR is called with the following URL: `http://192.168.0.1/test/john/mike/fred` then TEST will be used as the RRID. If the TEST record in RXSRTRCTL has -pgm *1 specified, then JOHN will be used as the program name, if -pgm *2 is specified, MIKE will be used as the program name, and so on. ### lib The **lib** flag defines the library of the program to be called. If the library is not in the library list, it will be added to the top of the library list. If the lib flag is not specified, *LIBL will be used. ### usrprf/passwd The **usrprf** and **passwd** flags define the user profile which the job should use whilst calling the program. If **usrprf** is specified, **passwd** must also be specified and vice-versa. If either the specified user profile or password are invalid or if the user profile is disabled, RXS Router will return an error to the browser and will not call the program. ### liblst The **liblst** flag defines the library list which should be used for the request. The liblst flag can be specified in one of two ways: - liblst library1,library2,library3 - liblst library/jobd If a comma-separated list of libraries is specified, they are each added in order to the bottom of the library list. If a qualified job description (*JOBD) is specified, the initial library list (INLLIBL) of the *JOBD is retrieved and the libraries are each added in order to the bottom of the library list. All libraries added as a result of the liblst flag are removed when control is returned from the called program. ### cvtopt See the [Control Data Conversion Options](#control-data-conversion-options) section for details of how the **cvtopt** flag should be specified. ### response See the [Calling non-CGI programs](#calling-non-cgi-programs) section for details of how the **response** flag should be specified. ### actgrp The **actgrp** flag defines the name of the activation group in which the program specified with the **pgm** flag will run. This value is ignored unless the program is specified with ACTGRP(\*CALLER). If the special value **-actgrp \*dftactgrp** is specified, the value specified for the **dftactgrp** flag in the \*CONFIG record will be used. If the **actgrp** flag is not specified and the program is defined with ACTGRP(\*CALLER), it will run in the same activation group as RXS Router - by default, this is the RXSRTR activation group. ### prdlib The **prdlib** flag specifies the name of the product library which is added to the library list prior to the program specified in the **pgm** flag being called. The product library is added above all user libraries, including the current library. This library will be removed after the program is called. If a value is specified for the **dftprdlib** flag in the *CONFIG record, that library will be overwritten by this value while the program is being called, and will be replaced afterwards. If the **prdlib** flag is not specified, but the **dftprdlib** flag is specified in the \*CONFIG record, that product library will be used for the duration of the program call. If the **prdlib** flag is not specified and the **dftprdlib** flag is not specified in the \*CONFIG record, no product library will be used for the duration of the program call. ## Example RXSRTRCTL Record | ID | DATA | |---|---| | ZAP | -pgm zappgm -liblst qgpl/zapjobd -lib qgpl -passwd donald -usrprf goofy | ## Control Data Conversion Options Depending on the value of the cvtopt control flag, RXSRTR may perform certain steps prior to calling the specified program. Some of the conversion options are designed to allow existing CGI programs which expect a particular value for the SCRIPT_NAME or QUERY_STRING environment variables to continue to be called as before, even though you may have changed the calling URL to implement RXSRTR control. Multiple conversion options can be combined in a comma-separated list. Each conversion option will be processed in the order it is found. The following sections describe the conversion options. ### rm_sn (Remove RRID from SCRIPT_NAME) The rm_sn conversion option indicates that if the RRID is included in the URL, it will be removed from the SCRIPT_NAME environment variable prior to the CGI program being called. If the rm_sn conversion option is specified and the URL used to call RXSRTR is: `http://192.168.0.1/rxsrtr/db2wse/mylib/myfile` then if the CGI program retrieves the SCRIPT_NAME environment variable, it will retrieve a value of `/db2wse/mylib/myfile` rather than the expected value of `/rxsrtr/db2wse/mylib/myfile` ### rm_qs (Remove RRID from QUERY_STRING) The rm_qs conversion option indicates that if the RRID is included in the URL, it will be removed from the QUERY_STRING environment variable prior to the CGI program being called. If the rm_qs conversion option is specified and the URL used to call RXSRTR is `http://192.168.0.1/cust/?fname=john&rxsrtr=mickey&lname=smith` then if the CGI program retrieves the QUERY_STRING environment variable, it will retrieve a value of `fname=john&lname=smith` rather than the expected value of `fname=john&rxsrtr=mickey&lname=smith` ### sn_pr (Parse parameters from SCRIPT_NAME) The sn_pr conversion option indicates that the program being called will be passed a number of parameters, as specified in the SCRIPT_NAME environment variable, where every path segment after the RRID will be treated as a separate character parameter. If the URL used to call RXSRTR is: `http://192.168.0.1/zap/mickey/mouse` and the ZAP control record has the following value: `-pgm zappgm -lib qgpl -cvtopt sn_pr` then RXSRTR will call program QGPL/ZAPPGM as follows: `CALL PGM(QGPL/ZAPPGM) PARM('MICKEY' 'MOUSE')` All parameters passed to the specified program will be passed as string pointers. In RPG, this means that they should be defined as follows: ```apache D ZAPPGM PR Extpgm('ZAPPGM') D fname * Const Options(*String) D lname * Const Options(*String) ``` ## Calling Non-CGI Programs CGI programs work by writing their output (typically the HTML for a web page) to 'standard output'. When the CGI program ends and control is returned to the HTTP server, the standard output is sent to the browser, displaying as a web page. However, if you use the HTTP server to call a non-CGI 'application' program, because it doesn't write to standard output, an HTTP 500 error page will appear. However, RXSRTR allows you to call a non-CGI application program, with the following limitations: - The program must be a batch (non-interactive) program - A maximum of 10 parameters can be passed to the program - All parameters must be defined in the program as character strings with a maximum length of 256 bytes If you wish to pass parameters to the program, you must specify the **sn_pr** conversion option, which will pass each of the SCRIPT_NAME path segments following the RRID as a character parameter. See the [Control Data Conversion Options](#control-data-conversion-options) section for details on how to specify this conversion option and the calling URL. When calling a non-CGI program, you must configure RXSRTR to send a response to the browser as an ad-hoc web-page, by specifying the response flag. It can be specified in one of the following two ways: `-response *confirm` or `-response *msg` After RXSRTR has called the program, it checks the value of the response flag. If -response *confirm is specified in the control record, RXSRTR will send a generic "Program called successfully" message to the browser. If -response *msg is specified, RXSRTR will retrieve the last message sent to it from the application program and will write it out to the browser. For instance, if an application program is typically called from a command-line or from a green-screen menu and sends a completion message (e.g. "Audit record created") to the screen, calling this program from RXSRTR and specifying -response *msg in the RXSRTRCTL record will cause this same message to be sent to the browser. ## Initializing RXS Router For performance reasons, when the RXS Router is first called within a job, it reads the records from the RXS Router control file RXSRTRCTL and caches the data into a user space called RXSRTRCTLU in the same library where the RXS Router itself exists. On subsequent calls within the same job, it uses the cached values, thus eliminating costly file I/O. However, if records in the RXSRTRCTL file are added, deleted or updated, the RXS Router cache must be updated. A command called [INZRXSRTR (Initialize RXS Router)](https://isupport.katointegrations.com/rxs/3.2/inzrxsrtr.md) is supplied with the RXS Router. When this command is run from a command line, the RXS Router cache is updated to contain the current values from the RXSRTRCTL file. This command can also be used to refresh the cached call pointers in Apache CGI jobs. This is useful because normally OS/400 will cache programs for reuse, but when you are doing web service development you will want Apache to pick up the latest version of the program after compiling it. Normally one would have to either recompile the entry level program to clear all cached call pointers or restart Apache. Neither of those options are optimal, so that is why we introduced the INZRXSRTR command to effectively refresh all cached call pointers. ## RXS Router Configuration Additional RXS Router configuration can be controlled by changing the options in the shipped *CONFIG record in the RXS Router control file RXSRTRCTL. The various control options are as follows: `routingid` : Routing identifier `loglvl` : Logging level (0, 1, or 2) `allowreset` : Allow *RESET option from client (*YES or *NO) `debugmode` : Run in debug mode(*YES or *NO) `dftactgrp` : Specifies the default activation group for CGI programs `dftliblst` : Specifies the default library list for CGI programs `dfterrpgm` : Specifies the default error-handling program `dftprdlib` : Specifies the default product library to use The *CONFIG record in the RXSRTRCTL file is shipped as follows: `-routingid rxsrtr -loglvl 0 -allowreset *no -debugmode *no` ### Control Option: routingid The **routingid** flag defines the type of routing that should be performed by RXSRTR. Depending on its value, RXSRTR will use either 'static' or 'dynamic' routing to determine the value of the request routing identifier (RRID), which actually defines the call definition. If the **routingid** flag is not specified, a value of 'RXSRTR' is assumed. For more information about how RXS Router retrieves and uses the routingid, see the page [Configuring RXS Router](https://isupport.katointegrations.com/rxs/3.2/configuring_rxs_router.md). ### Control Option: loglvl The **loglvl** flag defines the level of logging that will be performed by RXSRTR. There are three different logging levels available within RXSRTR: - **Log Level 0 (Error)** - Only errors encountered by RXSRTR during initialization or when processing a request are logged. - **Log Level 1 (Basic)** - All initialization information is logged, as well as basic information about each request, including user profile swaps, addition of libraries to the library list, routing identifiers used and the SCRIPT_NAME and QUERY_STRING values used for the request - **Log Level 2 (Full)** - Complete information about each request is logged, including parameter values and response data (where appropriate) All log entries are written to the RXSRTRLOG file, which contains a 1024-byte free-format field called DATA. Each log record consists of the following: | Start positionin DATA field | Length of data | Data | |:--------------------------:|---|:--------------:| | 1 | 1 | Log level ('0', '1', or '2') of log entry | | 3 | 26 | Qualified HTTP server job name | | 30 | 26 | Log entry timestamp | | 57 | 967 | Log entry data | If logging level 1 is specified, all logging at level 0 is also included. If logging level 2 is specified, all logging at logging level 0 and logging level 1 is also included. If the **loglvl** flag is not specified or is set to a value other than 0, 1 or 2, logging level 0 is assumed. ### Control Option: allowreset If the **allowreset** flag is set to \*YES, a user can reset the RXS Router from the browser by specifying a value of '\*RESET' in the URL (e.g. 'http://192.168.0.1/rxsrtr/*reset'). This will cause the RXS Router to reload all control records from the RXSRTRCTL file. It is recommended that a value of *YES is specified only if the RXS Router is being used on a development machine, since there is no checking to ensure which client used the reset option. If the **allowreset** flag is not specified or is set to a value other than *YES, a value of *NO is assumed. ### Control Option: debugmode If the **debugmode** flag is set to *YES, RXSRTR will run in debug mode. In this mode, instead of calling the specified program, RXSRTR will return a page displaying details of the program which would be called, as well as any the values of the QUERY_STRING and SCRIPT_NAME environment variables (if they have been changed due to any conversion options specified with the cvtopt flag). If the **debugmode** flag is not specified or is set to a value other than *YES, a value of *NO is assumed. ### Control Option: dftactgrp If the **dftactgrp** flag is specified, all programs called by RXS Router which are compiled with ACTGRP(*CALLER) will run using the specified activation group (unless the actgrp flag is specified in the RRID record for the program being called, in which case that value will be used instead). If the **dftactgrp** flag is not specified, all programs called by RXS Router which are compiled with ACTGRP(*CALLER) will run in the same activation group as RXS Router - by default this activation group is called RXSRTR. All programs called by RXS Router which are compiled with ACTGRP(*NEW) or ACTGRP(named-activation-group)) will run in the specified activation group. ### Control Option: dftliblst If the **dftliblst** flag is specified, the defined library list or list of libraries will be used for all CGI program calls. This flag can be provided either a comma-separated list of libraries or a qualified job description. If a comma-separated list of libraries is specified, there must be no spaces between each library and each comma. If a qualified job description is specified, e.g. -dftliblst qgpl/jobd, the initial library list (INLLIBL) for that job description is used. In either case, the specified list of libraries will replace the user portion of the CGI job's library list. No validation is performed when this flag is specified to check whether the job description or libraries exist, but runtime errors will occur. If the **dftliblst** flag is not specified, CGI program calls will use the default library list defined for the HTTP server (although see also the dftprdlib flag, which can alter the library list for CGI program calls). ### Control Option: dfterrpgm If the **dfterrpgm** flag is specified, the specified error-handling program will be called if the RXS Router encounters an error either when calling a specified program or during other processing. See the RXS Router user manual for details of the interface to the error handler and an example error handler. If the **dfterrpgm** flag is not specified, no default error handling program will be used. ### Control Option: dftprdlib If the **dftprdlib** flag is specified, the specified product library will be added to the library list when the RXS Router is called and is removed when the RXS Router returns control to the HTTP server. The product library is added above all user libraries, including the current library. If a value is specified for the prdlib flag in a user (non-*CONFIG) control record, this library will be overwritten by that value while the program is being called, and will be replaced afterwards. If the **dftprdlib** flag is not specified, no default product library will be used. --- # Create RXSRTR Environment (CRTRXSRTRE) > Creates a new RXS Router environment for use with RXSRTR. The Create RXSRTR Environment (CRTRXSRTRE) command allows the user to create a new environment for use with the [RXS Router](https://isupport.katointegrations.com/rxs/3.2/rxsrtr.md). ## Parameters ### Environment (ENV) This is a required parameter. Specify the name of the RXS Router environment to create. #### Possible Values: `character-value` : Name of the RXS Router environment to create. ### Text 'description' (TEXT) Describes the environment being created. #### Possible Values: `*BLANK` : No description. `character-value` : Description of the RXS Router environment being created. ### Copy from environment (FROMENV) Specify the name of the existing environment from which to copy the control records. #### Possible Values: `*DFT` : The new environment is copied from the default RXSRTR environment. `character-value` : Specify the name of the environment to copy. ### Records to copy (CPYENVOPT) Specify which records to copy from the existing environment. #### Possible Values: `*ALL` : All control records are copied from the specified environment. `*CFG` : Only the *CONFIG record is copied from the specified environment. ### Data library (DTALIB) Specify the RXS Router data library. The RXS Router data library contains data objects required by the RXS Router runtime, including copies of the control file, log file and data cache. #### Possible Values: `*LIBL` : The first library in the library list of the current job which contains the objects specified above will be used. `data-library` : The specified library will be used. --- # Work with RXSRTR Entries (WRKRXSRTRE) > Interactive command to create, modify, and delete RXS Router routing entries in RXSRTRCTL. The Work with RXSRTRCTL Entries (WRKRXSRTRE) command allows the user to create, modify, and delete configuration entries for use with the RXS Router. The command consists of two screens - the main entry display screen, and the entry detail display screen. From the main entry display screen, you can select one or more entries to be displayed, edited or deleted, using the subfile selector field on the left side. You can also use the F6 key to create a new entry. You can use the input field at the top of the screen to position to an entry. ![Work with RXSRTRCTL Entries](https://isupport.katointegrations.com/llms/rpg-api-express-3.2/maindisplay.png) On the main entry display screen, only the first few characters of each entry are displayed. On the entry detail display screen, you can display the full entry details and edit them if necessary. Each entry consists of a string comprised of one or more 'flags' followed by a related value. ![RXSRTRCTL Entry Detail](https://isupport.katointegrations.com/llms/rpg-api-express-3.2/entrydetail.png) For more information about how to create a valid RXS Router entry to meet your specific needs, please read more about [RXS Router](https://isupport.katointegrations.com/rxs/3.2/rxsrtr.md). ## Parameters ### Environment (ENV) Specifies the name of the RXS Router environment to edit. This corresponds to same-named members in the RXSRTRCTL and RXSRTRLOG files and a user space of the same name. #### Possible Values: `*DFT` : The default environment called RXSRTR will be used. `character-value` : Name of the RXS Router environment to work with. ### Data library (DTALIB) Specify the RXS Router data library. The RXS Router data library contains data objects required by the RXS Router runtime, including copies of the control file, log file and data cache. #### Possible Values: `*LIBL` : The first library in the library list of the current job which contains the objects specified above will be used. `data-library` : The specified library will be used. ### Routing Identifier (ID) Specify the routing control entry to work with. #### Possible Values: `*ALL` : All routing control entries will be displayed. The user can specify entries for display, edit or delete or can create a new entry. `routing-identifier` : The specified routing control entry will be displayed in edit mode. --- # Initialize RXS Router (INZRXSRTR) > Refreshes the RXS Router cache from RXSRTRCTL and clears cached call pointers in Apache CGI jobs. The INZRXSRTR (Initialize RXS Router) command is supplied with the RXS Router. When this command is run from a command line, the RXS Router cache is updated to contain the current values from the RXSRTRCTL file. This command can also be used to refresh the cached call pointers in Apache CGI jobs. This is useful because normally OS/400 will cache programs for reuse, but when you are doing web service development you will want Apache to pick up the latest version of the program after compiling it. Normally one would have to either recompile the entry level program to clear all cached call pointers or restart Apache. Neither of those options are optimal, so that is why we introduced the INZRXSRTR command to effectively refresh all cached call pointers. ## Parameters ### Environment (ENV) Specifies the name of the RXS Router environment to initialize. This corresponds to same-named members in the RXSRTRCTL and RXSRTRLOG files and a user space of the same name. Note: If the RXSRTR environment does not exist, no error message will be displayed. #### Possible Values: `*ALL` : All RXSRTR environments will be initialized. `*DFT` : The default environment called RXSRTR will be initialized. `character-value` : Name of the RXSRTR environment to initialize. ### Data library (DTALIB) Specify the RXS Router data library. The RXS Router data library contains data objects required by the RXS Router runtime, including copies of the control file, log file and data cache. #### Possible Values: `*LIBL` : The first library in the library list of the current job which contains the objects specified above will be used. `data-library` : The specified library will be used. --- # Build Template (BLDTPL) > Generates a compiled template (.tpl) file from a sample XML document for use with the RXS composition engine. The BLDTPL command aids in composing RPG-XML Suite template (*.tpl) files. These are then converted using the CRTRPGTPL Command, which are in turn used with the Template/Composition Engine subprocedures (RXS_StartComposeEngine(), RXS_ComposeSection, RXS_ComposeVariable(), and RXS_GetComposeBuffer()) to compose XML documents. **Note: You will need to make manual modifications to the generated .tpl file prior to using it with the CRTRPGTPL Command.** **Please follow our example on [Creating an RXS Template](https://isupport.katointegrations.com/rxs/3.2/creating_an_rxs_template.md) to understand this process.** ## Parameters ### IFS XML Location (IFSXMLLOC) This is a required parameter. Specify an IFS file path to the stream file containing your XML to build the template from. **This must be a fully qualified file path.** #### Possible Values: `character-value` : IFS path to XML file to build template from. ### IFS Template Location (IFSTPLLOC) This is a required parameter. Specify an IFS file path to the location the generated .tpl file should be build. **This must be a fully qualified file path.** #### Possible Values: `character-value` : IFS path to create .tpl file at. ### Indent Length (INDENT) Specify how many spaces should be used when indenting the created .tpl file. #### Possible Values: `numeric-value` : Number of spaces used for indentation. --- # Create RPG Template (CRTRPGTPL) > Compiles an RXS template source file (.tpl) into a bound service program for use in RPG composition engine calls. Use this command to create a RPG version of any template files needed for your program. Starting with version 3.0 of RPG-XML Suite, you no longer reference template files in the IFS at runtime. Instead, use this command to convert the stream file to an RPG version of the template. The RPG source is created for you from the template, and if the template should ever change, you will need to re-run this command and recompile your RPG program. If you don't currently have an RXS template file, you will need to use [BLDTPL](https://isupport.katointegrations.com/rxs/3.2/bldtpl.md) to build one. ## Parameters ### Stream file (STMF) This is a required parameter. Specifies the full path of the IFS stream file built manually or with the BLDTPL Command. ### Source file (FILE) Specifies the name of the source and library of the physical file that will contain the generated RPG source code. --- # Build Parsing Subprocedure (BLDPRS) > Generates an RPG handler subprocedure for XML or JSON event-based parsing from a sample document. The BLDPRS command is used to aid in writing RPG-XML Suite XML parsing code to be used with the [RXS_Parse() subprocedure](https://isupport.katointegrations.com/rxs/3.2/rxs_parse.md). RXS_Parse() relies on a "handler" subprocedure which can capture various XML parsing events, giving you access to the data in an XML document. Note: You will need to make manual modifications to the generated parsing "handler" in addition to importing it into your program. Please follow our example on [Creating an XML Parsing Subprocedure](https://isupport.katointegrations.com/rxs/3.2/creating_an_xml_parsing_subprocedure.md) to understand this process. ## Parameters ### Source Library (SRCLIB) This is a required parameter. Specify the library name where your parsing handler subprocedure source file member should be created. #### Possible Values: `character-value` : Library name to create the source file member in. ### Source File (SRCPF) This is a required parameter. Specify the file name where your parsing handler subprocedure source file member should be created. #### Possible Values: `character-value` : File name to create the source file member in. ### Source Member (SRCMBR) This is a required parameter. Specify the member name where your parsing handler subprocedure source file member should be created. #### Possible Values: `character-value` : Member name to hold the generated parsing handler subprocedure. ### IFS XML Location (IFSXMLLOC) This is a required parameter. Specify an IFS file path to the stream file containing your XML to build the parsing handler subprocedure from. This must be a fully qualified file path. #### Possible Values: `character-value` : IFS path to XML file to build parsing handler subprocedure from. ### Base Envelope (BASEENV) This is a required parameter. Specify the beginning portion of an XPath that is repeated for every element or attribute in the XML document. #### Possible Values: `character-value` : XPath to use as the base path to simplify code generation. ### Generate Content Parsing (XMLCONTENT) Specify whether or not XML "content" events should be captured in the generated parsing handler subprocedure. #### Possible Values: `*YES` : Generate XML "content" events `*NO` : Do not generate XML "content" events ### Generate Begin Element Parsing (XMLBEGIN) Specify whether or not XML "begin element" events should be captured in the generated parsing handler subprocedure. #### Possible Values: `*YES` : Generate XML "begin element" events `*NO` : Do not generate XML "begin element" events ### Generate End Element Parsing (XMLBEGIN) Specify whether or not XML "end element" events should be captured in the generated parsing handler subprocedure. #### Possible Values: `*YES` : Generate XML "end element" events `*NO` : Do not generate XML "end element" events ### Generate Attribute Parsing (XMLBEGIN) Specify whether or not XML "attribute" events should be captured in the generated parsing handler subprocedure. #### Possible Values: `*YES` : Generate XML "attribute" events `*NO` : Do not generate XML "attribute" events --- # Creating an RXS Template > Tutorial for creating a compiled XML template using BLDTPL and CRTRPGTPL, covering variable placeholders and section declarations. To generate XML, RPG-XML Suite relies on what is referred to as the "template engine" or "composition engine". This engine uses a specially marked up psuedo-XML file divided into sections and with variable fields embedded in it as well as a set of RPG-XML Suite subprocedures. The combination of the template file and the subprocedures allow you to build XML of any complexity or depth needed to meet your business requirements. This tutorial will demonstrate using the following commands in sequence to generate a compiled XML template: - [BLDTPL](https://isupport.katointegrations.com/rxs/3.2/bldtpl.md) - [CRTRPGTPL](https://isupport.katointegrations.com/rxs/3.2/crtrpgtpl.md) Once our compiled template is generated, we will also write a short example program. ## Generating the IFS Template File (BLDTPL) To start with creating a template file, we first need to create a file in the IFS. This file will be populated with our sample XML data, which will be used to generate the template. The command below uses QSHELL to create an IFS stream file using CCSID 819. This CCSID is **strongly** recommended when creating IFS files for use with RXS tools. Note that this command is **case-sensitive**. `QSH CMD('touch -C 819 /www/myrxs/templates/postadr.xml')` Note that, for the purposes of this tutorial, we're generating this example file in the /www/myrxs/templates directory. For many of our customers, this directory was created during their initial installation of RPG-XML Suite. This is not the only valid location for template files in the IFS - you can generate and store your XML and template files in any directory. Next, we need to populate this file with a sample of the XML that we're going to use as the basis of the template. This sample document should be as complete as possible. If your XML has many optional fields, try to include them all in this sample file, even if some of them would not logically appear with others in normal usage. To get the XML into our IFS stream file, we'll use the EDTF command: `EDTF '/www/myrxs/templates/postadr.xml'` Now, paste your sample XML into the resulting editor window. This sample XML may or may not contain data in any or all fields - this will not impact the template output. ```xml Jamie Hale 2886 Veltri Dr Hickory Hills VA 94124 949-555-4671 ``` While in the Edit File editor select F2 to save the document changes. Once the sample XML file is saved, call the [BLDTPL](https://isupport.katointegrations.com/rxs/3.2/bldtpl.md) command and specify the fully-qualified filepath for the sample XML file in the first parameter, and the fully-qualified filepath for where the generated .tpl template file should be written in the second parameter: `BLDTPL SRCSTMF('/www/myrxs/templates/postadr.xml') OUTSTMF('/www/myrxs/templates/postadr.tpl') INDENT(2)` The third parameter, `INDENT`, is optional and controls how many spaces are used to indent each nested element in the generated template file. The default value is 2. There are two primary components to an RPG-XML Suite XML template file: 1. **Variables** are placeholders used to indicate where data will be composed into the XML document by the [RXS_ComposeVariable()](https://isupport.katointegrations.com/rxs/3.2/rxs_composevariable.md) subprocedure. These are declared with the format `.:variable:.`. 2. **Sections** are used to denote a "chunk" of the XML document that should be written to the buffer in a single call to [RXS_ComposeSection()](https://isupport.katointegrations.com/rxs/3.2/rxs_composesection.md). Sections are declared with the format `::section`. Each template must include a **minimum of one section**, and the first line in any template must be a section declaration. Sections are not automatically generated in the BLDTPL output - you will need to manually add them yourself based on your knowledge and understanding of how the document is meant to be composed and would best be divided. Below is the generated template file located at /www/myrxs/templates/postadr.tpl - use EDTF to view it. Note that all elements and attributes have had their values replaced with the variable placeholders respective to the element or attribute's name. Also note that there are no sections present in the generated output. ```xml .:first:. .:last:. .:street:. .:city:. .:state:. .:zip:. .:phone:. ``` An important thing to note is that in the generated template file, there is only one `` element, where before there were two. Repeating elements are generally handled using sections, as described below, rather than duplicating lines in the template. Now that our template is generated with the variable placeholders, we need to add our sections. We'll need to add at least one section at the beginning of the document. Since our `` element is a repeating element, we will give that its own section as well. Finally, we'll add a closing section to write the end tags for the document. Here is an example of our edited template file, including the sections we've added: ```xml ::PostAdr_beg .:first:. .:last:. .:street:. .:city:. .:state:. .:zip:. ::Phone .:phone:. ::PostAdr_end ``` By giving the `` element a separate section, it gives us the flexibility to write as many of those elements as we need by calling RXS_ComposeVariable() to populate the `phone` variable, then RXS_ComposeSection() to write the `Phone` section for that phone number. Not all sections in an XML document need to be used during XML composition. Sections of your XML may be optional - unused depending upon your business logic or a specific request's needs. In our example, if we did not have a phone number for a given address, we may not compose the `Phone` section for that entry at all. ## Generating the Compiled RPG Template (CRTRPGTPL) Now that we have our IFS template file set up with our sections, we are going to use the [CRTRPGTPL](https://isupport.katointegrations.com/rxs/3.2/crtrpgtpl.md) command to convert our template file into an RPG source member. This RPG source member will be compiled directly into your RPG-XML Suite-enabled program using the `/COPY` compiler directive. For demonstration purposes, we will generate the compiled template into the QRPGLETPL source physical file in the RXS library. It is **strongly recommended** that you never store your code members in any RXS library. **Note:** the command will specify a name of *FIRST for the member by default. You need to change this value - we generally recommend specifying the same name as the program you're going to use this template with, or the name of the IFS template file. `CRTRPGTPL STMF('/www/myrxs/templates/postadr.tpl') FILE(RXS/QRPGLETPL) MBR(POSTADR) SECTIONSDS(S) VARSDS(V)` It's also important to note that we're specifying values for SECTIONSDS and VARSDS. These parameters are not set by default, but specifying values allows CRTRPGTPL to build qualified data structures for the section and variable names. This helps improve code readability and helps keep the template engine fields separate from your normal RPG code. This is not required, but very strongly recommended. Once this command has completed, you can open up the source physical file RXS/QRPGLETPL and look at member POSTADR using PDM or RDi. It should look like this: ```rpgle /IF NOT DEFINED(POSTADR) /DEFINE POSTADR D S... D DS Qualified D PostAdr_beg... D 50A Varying D phone... D 50A Varying D PostAdr_end... D 50A Varying D V... D DS Qualified D residential... D 30A Varying D title... D 30A Varying D first... D 30A Varying D last... D 30A Varying D street... D 30A Varying D city... D 30A Varying D state... D 30A Varying D zip... D 30A Varying D phone... D 30A Varying /EOF /ENDIF /free S.PostAdr_beg = 'PostAdr_beg'; S.phone = 'phone'; S.PostAdr_end = 'PostAdr_end'; V.residential = 'residential'; V.title = 'title'; V.first = 'first'; V.last = 'last'; V.street = 'street'; V.city = 'city'; V.state = 'state'; V.zip = 'zip'; V.phone = 'phone'; p = ''; p += '::PostAdr_beg' + x'15'; p += '' + x'15'; p += ' ' + x'15'; p += ' ' + '.:first:.' + '' + x'15'; p += ' ' + '.:last:.' + '' + x'15'; p += ' ' + x'15'; p += ' ' + '.:street:.' + '' + x'15'; p += ' ' + '.:city:.' + '' + x'15'; p += ' ' + '.:state:.' + '' + x'15'; p += ' ' + '.:zip:.' + '' + x'15'; p += '::phone' + x'15'; p += ' ' + '.:phone:.' + '' + x'15'; p += '::PostAdr_end' + x'15'; p += '' + x'15'; /end-free ``` As you can see, the resulting template file is quite literally RPG code. The section and variable names have been added to the S and V data structures, and the template content itself is included below in the format expected by the XML composition engine. One of the benefits of this approach is that, because the template section and variable names are RPG fields, it's very easy to catch typos in your program because the program simply won't compile. **Note: It is imperative that you *never edit or modify* the source member generated by the CRTRPGTPL command in any way, unless directed to do so by a member of our support staff.** If you need to make changes to your template, first update the corresponding .tpl file in the IFS, then run CRTRPGTPL on that updated .tpl file to regenerate the compiled template member. ## Using the RPG Template With the Composition Engine Now that we have our compiled template, we will bring this template into our RPG program and use the XML composition engine subprocedures to build our XML. Here is an example program using our POSTADR template: ```rpgle H DEBUG(*YES) DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /copy QRPGLECPY,RXSCB /copy QRPGLETPL,POSTADR D Template PR D p Like(RXS_TEMPLATE_PARM) D XML S Like(RXS_Var64Kv_t) D i S 3I 0 D ComposeDS DS LikeDS(RXS_ComposeDS_t) D Inz(*LikeDS) /free monitor; RXS_ResetDS( ComposeDS : RXS_DS_TYPE_COMPOSE ); ComposeDS.TemplateProcedure = %Paddr(Template); RXS_StartComposeEngine( ComposeDS ); RXS_ComposeVariable( V.residential : 'true'); RXS_ComposeVariable( V.title : 'Mr.' ); RXS_ComposeVariable( V.first : 'Sample' ); RXS_ComposeVariable( V.last : 'Resident' ); RXS_ComposeVariable( V.street : '999 Totally A Real Street' ); RXS_ComposeVariable( V.city : 'Cityville' ); RXS_ComposeVariable( V.state : 'OH' ); RXS_ComposeVariable( V.zip : '12345' ); RXS_ComposeSection( S.PostAdr_beg ); for i = 1 to 3 by 1; RXS_ComposeVariable( V.phone : '987-654-321' + %Char(i) ); RXS_ComposeSection( S.phone ); endfor; RXS_ComposeSection( S.PostAdr_end ); XML = RXS_GetComposeBuffer(); RXS_JobLog( XML ); on-error; endmon; *Inlr = *On; /end-free P Template B D PI D p Like(RXS_TEMPLATE_PARM) /copy QRPGLETPL,POSTADR P E ``` The end result of this program will be XML written out to the job log that looks like the following: ```xml Jamie Hale 2886 Veltri Dr Hickory Hills VA 94124 949-555-4671 949-555-4672 949-555-4673 ``` --- # Creating an XML Parsing Subprocedure > Tutorial for generating an XML event handler subprocedure using BLDPRS, covering event type selection and integration into RPG programs. The BLDPRS command is used to aid in writing RPG-XML Suite XML parsing code to be used with the [RXS_Parse()](https://isupport.katointegrations.com/rxs/3.2/rxs_parse.md) subprocedure. In the examples included with RPG-XML Suite (i.e. MYRXS/EXAMPLE,*) there are many "handler" or parsing subprocedures that take an XML file and parse it for the data contents. After writing a few of these parsing subprocedures you will find that much of keying is repetitive with just a few things changing from program to program. Instead of doing this manually, the BLDPRS command can be used to generate a parsing subprocedure that can get you most of the way to a functioning parsing subprocedure. BLDPRS usage can best be explained with an example. The first thing needed is an XML document residing in the IFS. Type the following on the command line to create an XML file named /home/bldprs001.xml in the IFS. `QSH CMD('touch -C 819 /home/bldprs001.xml')` The file now exists but without content. To add content we will use the EDTF command and copy/paste the following XML. `EDTF '/home/bldprs001.xml'` Add the following XML to the file: ```xml Sample Resident 123 Center Rd Mankato MN 56001 123-123-1234 321-321-4321 ``` While in the Edit File editor select F2 to save the document changes. Now it is time to invoke the BLDPRS command to generate the parsing code. You will need to provide the library, source physical file, and source member of where you would like the generated code to be placed and also where the XML document resides in the IFS that should be used. The last parameter, BASEENV, can be omitted but serves a code readability purpose. BASEENV allows you to specify the beginning portion of an XPath that is repeated for every element, or attribute, in the XML document. In the below example /PostAdr is specified for the BASEENV parameter. This value will be applied to an RPG variable named baseEnv and baseEnv will then be used in the WHEN clauses to make the statements shorter. `BLDPRS SRCLIB(RXS) SRCPF(EXAMPLE) SRCMBR(BLDPRS001) IFSXMLLOC('/home/bldprs001.xml') BASEENV('/PostAdr')` The following is the contents of source member RXS/EXAMPLE,BLDPRS001 after running the above command. Note that some of the code was omitted for brevity's sake. ```rpgle D allHandler pr D pType value like(RXS_Type) D pXPath value like(RXS_XPath) D pData value like(RXS_XmlData) D pDataLen value like(RXS_Length) //----------------------------------------------------------------- // @Author: // @Created: // @Desc: //----------------------------------------------------------------- P allHandler b D allHandler pi D pType value like(RXS_Type) D pXPath value like(RXS_XPath) D pData value like(RXS_XmlData) D pDataLen value like(RXS_Length) D chgMe s like(RXS_XmlData) D baseEnv s 70a varying /free baseEnv = '/PostAdr'; select; when pXPath = baseEnv +'>'; chgMe = pData; when pXPath = baseEnv +'@residential'; chgMe = pData; when pXPath = baseEnv +'/'; chgMe = pData; when pXPath = baseEnv +'/name>'; chgMe = pData; when pXPath = baseEnv +'/name@title'; chgMe = pData; when pXPath = baseEnv +'/name/'; chgMe = pData; when pXPath = baseEnv +'/name/first>'; chgMe = pData; when pXPath = baseEnv +'/name/first/'; chgMe = pData; when pXPath = baseEnv +'/name/first/>'; chgMe = pData; when pXPath = baseEnv +'/name/last>'; chgMe = pData; when pXPath = baseEnv +'/name/last/'; chgMe = pData; when pXPath = baseEnv +'/name/last/>'; chgMe = pData; when pXPath = baseEnv +'/name/>'; chgMe = pData; when pXPath = baseEnv +'/street>'; chgMe = pData; when pXPath = baseEnv +'/street/'; chgMe = pData; when pXPath = baseEnv +'/street/>'; chgMe = pData; ... when pXPath = baseEnv +'/>'; chgMe = pData; endsl; /end-free P e ``` One thing you'll note is that by default BLDPRS will generate a parsing subprocedure meant to handle all possible events. However, Element Begin (e.g. /ELEMENT> ) and Element End (e.g. /ELEMENT/> ) events are frequently unused. BLDPRS has the capability to exclude certain types of events when generating the parsing code through the parameters XMLCONTENT, XMLBEGIN, XMLEND, and XMLATTR. Each of those can have a value of *YES or *NO, but at least one of them must have a value of *YES or there will be no events to generate a subprocedure for. To generate a subprocedure with only Content (e.g. /ELEMENT/ ) events, you could do the following: `BLDPRS SRCLIB(MYRXS) SRCPF(EXAMPLE) SRCMBR(BLDPRS001) IFSXMLLOC('/home/bldprs001.xml') BASEENV('/PostAdr') XMLCONTENT(*YES) XMLBEGIN(*NO) XMLEND(*NO) XMLATTR(*NO)` This would generate an XML parsing subprocedure like this: ```rpgle D allHandler pr D pType value like(RXS_Type) D pXPath value like(RXS_XPath) D pData value like(RXS_XmlData) D pDataLen value like(RXS_Length) //----------------------------------------------------------------- // @Author: // @Created: // @Desc: //----------------------------------------------------------------- P allHandler b D allHandler pi D pType value like(RXS_Type) D pXPath value like(RXS_XPath) D pData value like(RXS_XmlData) D pDataLen value like(RXS_Length) D chgMe s like(RXS_XmlData) D baseEnv s 70a varying /free baseEnv = '/PostAdr'; select; when pXPath = baseEnv +'/'; chgMe = pData; when pXPath = baseEnv +'/name/'; chgMe = pData; when pXPath = baseEnv +'/name/first/'; chgMe = pData; when pXPath = baseEnv +'/name/last/'; chgMe = pData; when pXPath = baseEnv +'/street/'; chgMe = pData; ... endsl; /end-free P e ``` It's important to note that the code generated by BLDPRS will require some modifications to bring it in line with the new model for parsing subprocedures introduced in RXS3. The most important parts you'll need to replace are the procedure prototype and interface. Additionally, because the parsing subprocedure utilizes pointers instead of native character fields, the subprocedure [RXS_STR()](https://isupport.katointegrations.com/rxs/3.2/rxs_str.md) must be used to convert. Below is what the above sample would look like modified to be compatible with RXS3. ### IBM i 7.1+ Example Code ```rpgle D XmlHandler PR D pType 10A Value D pXPath 1024A Value Varying D pData * Value D pDataLen 10I 0 Value //----------------------------------------------------------------- // @Author: // @Created: // @Desc: //----------------------------------------------------------------- P XmlHandler B D XmlHandler PI D pType 10A Value D pXPath 1024A Value Varying D pData * Value D pDataLen 10I 0 Value D chgMe S Like(RXS_Var1Kv_t) D baseEnv S 70a varying /free baseEnv = '/PostAdr'; select; when pXPath = baseEnv +'/'; chgMe = RXS_STR( pData : pDataLen ); when pXPath = baseEnv +'/name/'; chgMe = RXS_STR( pData : pDataLen ); when pXPath = baseEnv +'/name/first/'; chgMe = RXS_STR( pData : pDataLen ); when pXPath = baseEnv +'/name/last/'; chgMe = RXS_STR( pData : pDataLen ); when pXPath = baseEnv +'/street/'; chgMe = RXS_STR( pData : pDataLen ); ... endsl; /end-free P E ``` ### IBM i 6.1 Example Code ```rpgle D XmlHandler PR D pType 10A Value D pXPath 1024A Value Varying D pData * Value D pDataLen 10I 0 Value //----------------------------------------------------------------- // @Author: // @Created: // @Desc: //----------------------------------------------------------------- P XmlHandler B D XmlHandler PI D pType 10A Value D pXPath 1024A Value Varying D pData * Value D pDataLen 10I 0 Value D chgMe S Like(RXS_Var1Kv_t) D baseEnv S 70a varying /free baseEnv = '/PostAdr'; select; when pXPath = baseEnv +'/'; RXS_STR( chgMe : pData : pDataLen ); when pXPath = baseEnv +'/name/'; RXS_STR( chgMe : pData : pDataLen ); when pXPath = baseEnv +'/name/first/'; RXS_STR( chgMe : pData : pDataLen ); when pXPath = baseEnv +'/name/last/'; RXS_STR( chgMe : pData : pDataLen ); when pXPath = baseEnv +'/street/'; RXS_STR( chgMe : pData : pDataLen ); ... endsl; /end-free P E ``` --- # Configuring RXS Router > Two-stage guide to configuring Apache httpd.conf for RXS CGI routing and setting up static or dynamic RXSRTR routing entries. There are two main stages to routing configuration when using RXS Router. The first happens through the Apache configuration file - httpd.conf - which is typically in an IFS path like `/www/rxs/conf/httpd.conf` or `/www/myrxs/conf/httpd.conf`. The second stage happens within RXS Router and the RXS Router environments on your system. ## Apache Configuration RXS Router determines which environment to load based on the value of the RXSRTR_ENVIRONMENT variable, which is set by Apache. The first step is to add the following directive to your httpd.conf file: ```apache ScriptAliasMatch ^/(([^/.]+/)*[^/.]+)$ /qsys.lib/RXS.lib/rxsrtr.pgm Options +ExecCGI Allow From all ``` This directive tells Apache to call RXSRTR for every URL on which it is listening. This will allow Apache to transfer control to RXS Router, which will then run the associated programs before returning any output to Apache. RXS Router checks the RXSRTR_ENVIRONMENT variable to determine which configuration should be loaded for a given request. This environment variable value is set by Apache. For each path which has a corresponding RXS Router environment, a Location element must be added to httpd.conf: ```apache SetEnv RXSRTR_ENVIRONMENT 'MYRXS' ``` The value of '/myrxs/' should be substituted by your desired URL path, and the value of 'MYRXS' should correspond to the RXS Router environment that should be loaded. ## RXS Router Configuration The configuration of your RXS Router environment depends on which type of routing you are using - static or dynamic. Configuration records are stored in control files, which are accessible with the [WRKRXSRTRE](https://isupport.katointegrations.com/rxs/3.2/wrkrxsrtre.md) command. ### Routing #### Static (environment variable) routing If the **routingid flag** has a value which begins with `ENVVAR:`, RXSRTR will check the specified environment variable on each request to determine the RRID. For instance, if the routingid flag is specified as follows: `-routingid envvar:http_soapaction` then whenever RXSRTR is called by the HTTP server, it will retrieve the value of the HTTP_SOAPACTION environment variable and will use that value as the RRID. This processing will be performed for every request handled by RXSRTR, irrespective of the actual URL used. If the specified environment variable is a path name, you may specify a qualifier of a colon followed by a slash, immediately following the environment variable name, e.g.: `-routingid envvar:http_soapaction:/` and RXSRTR will use only the last path segment of the environment variable as the RRID. For instance, if the value of the HTTP_SOAPACTION variable is `https://www.mycompany.com/webservices/local/values/focus/getasset` then the RRID used would be 'GETASSET'. #### Dynamic routing If the **routingid** flag has a value which does not begin with `ENVVAR:`, RXSRTR will use 'dynamic' routing, whereby the actual URL used by the client will be parsed to determine the RRID. RXSRTR uses the following steps to determine the RRID from the URL (as soon as the RRID has been determined, further steps are bypassed): 1. The value of the QUERY_STRING environment variable is retrieved as {querystring} 2. The SCRIPT_NAME environment variable is retrieved as {scriptname} and parsed into its constituent 'segments'. For instance, a SCRIPT_NAME value of /rxsrtr/petstore/item' is parsed into 3 separate segments - 'rxsrtr', 'petstore' and 'item'. All values are converted to upper-case for comparison purposes during parsing. 3. If one of the {scriptname} segments has a value of routingid and the next segment is not blank, that next segment is used as the RRID. 4. If {querystring} is blank, the first {scriptname} segment (retrieved in step 2) is used as the RRID. 5. If one of the variables in {querystring} is routingid, its value is used as the RRID. 6. Otherwise the first {scriptname} segment is used as the RRID. This means that all of the following example URI's will result in an RRID of 'MICKEY' (assuming that the value of the routingid flag has the default value of 'RXSRTR') 7. `http://192.168.0.1/rxsrtr/mickey/foo/bar` 8. `http://192.168.0.1/mickey/foo/bar` 9. `http://192.168.0.1/foo/bar?fname=john&rxsrtr=mickey&lname=smith` 10. `http://192.168.0.1/mickey/foo/bar?fname=john&lname=smith` In case 1, RXSRTR is specified as a path segment and the subsequent path segment is not blank, so it is used as the RRID. In case 2, RXSRTR is not specified as any of the path segments, and the QUERY_STRING variable is blank, so the first path segment is used as the RRID. In case 3, RXSRTR is not specified as any of the path segments. However, the QUERY_STRING variable does contain a variable called RXSRTR, so that variable's value is used as the RRID. In case 4, RXSRTR is not specified as any of the path segments, and the none of the QUERY_STRING variables is called 'RXSRTR', so the first path segment is used as the RRID. ### RXSRTRCTL Entries Configuration entries for RXS Router are managed using [WRKRXSRTRE](https://isupport.katointegrations.com/rxs/3.2/wrkrxsrtre.md). For a given RXS Router control file, there will be two or more individual entries, which are used to determine what programs are called by RXS Router. Each control file must contain a \*CONFIG entry. This entry is loaded first by RXS Router, and is used to determine which record in the environment is loaded for the final routing stage. More information about the options used by \*CONFIG can be found on the [RXS Router](https://isupport.katointegrations.com/rxs/3.2/rxsrtr.md) page. The default value for the routing ID is **RXSRTR**, which instructs RXS Router to use dynamic routing to determine which control file record to load, based on the URL. For static routing, RXS Router will refer to the value of the specified environment variable to determine the correct control file record, and the routing ID flag must be specified using the `ENVVAR:` prefix. Subsequent entries within your RXS Router control file contain configuration information for calling a specific program. RXS Router determines which of these records to invoke using the criteria outlined in the [Routing](#routing) section. There are many flags that can be specified for a given routing ID, but the only required one is `-pgm`, which tells RXS Router which program should be called. The `-pgm` flag can either contain the name of a program or a special value (\*0-\*9). If a name is specified, RXS Router will search through the library list of the job for a match, or look in the library specified in the `-lib` tag. If a special value is used, RXS Router will refer to the URL path to determine which program should be called. #### With Name The following configuration will run the program DEMOSVC in the library MYRXS: `-pgm DEMOSVC -lib MYRXS` #### With Special Value The following configuration will dynamically determine the program to be called, based on the URL, within the library list of the job decription (\*JOBD) specified by the `-liblst` flag: `-pgm *1 -liblst MYRXS/RTRJOB` The special value of \*0 corresponds to the routing ID, while \*1-\*9 represent URL path segments. If the service was called using the following URL: `https:/api.myservice.com/myrxs/demosvc/` the routing ID will be MYRXS, and RXS Router will call the program DEMOSVC. --- # CELSIUS > Example RPG program demonstrating the basic structure of an RPG API Express program that composes an XML request, calls a remote web service, and parses the XML response. This example program demonstrates the basic structure of an RPG program utilizing RPG-XML Suite to compose an XML request, call a remote web service, and parse the response XML. ```rpgle H DEBUG(*YES) DFTACTGRP(*NO) BNDDIR('RXSBND') ACTGRP(*CALLER) /DEFINE RXSV6R1 /copy QRPGLECPY,RXSCB /copy QRPGLETPL,CELSIUS D Template PR D p Like(RXS_TEMPLATE_PARM) D XmlHandler PR D pType 10A Value D pXPath 1024A Value Varying D pData * Value D pDataLen 10I 0 Value D gFahrenheit S 10I 0 D gCelsius S 10I 0 D gXmlRequest S Like(RXS_Var64Kv_t) D gXmlResponse S Like(RXS_Var64Kv_t) D ComposeDS DS LikeDS(RXS_ComposeDS_t) D TransmitDS DS LikeDS(RXS_TransmitDS_t) D ParseDS DS LikeDS(RXS_ParseDS_t) D ErrorDS DS LikeDS(RXS_CatchThrowErrorDS_t) /free *Inlr = *On; monitor; gFahrenheit = 100; exsr compose; exsr transmit; exsr parse; RXS_ResetDS( ErrorDS : RXS_DS_TYPE_CATCHTHROWERROR ); ErrorDS.MessageId = 'RXS9897'; ErrorDS.MessageData = 'Celsius Temp: ' + %trim ( %editc( gCelsius : '3' ) + '°'); ErrorDS.ThrowToCaller = RXS_YES; RXS_Throw( ErrorDS ); on-error; endmon; begsr compose; RXS_ResetDS( ComposeDS : RXS_DS_TYPE_COMPOSE ); ComposeDS.TemplateProcedure = %paddr(Template); RXS_StartComposeEngine(ComposeDS); RXS_ComposeVariable( fahrenheit : %Char(gFahrenheit) ); RXS_ComposeSection( content ); RXS_GetComposeBuffer(gXmlRequest); endsr; begsr transmit; RXS_ResetDS( TransmitDS : RXS_DS_TYPE_TRANSMIT ); TransmitDS.URI = 'http://www.w3schools.com/webservices/tempconvert.asmx'; TransmitDS.HeaderSOAPAction = '"http://www.w3schools.com/webservices/FahrenheitToCelsius"'; TransmitDS.LogFile = '/tmp/celsius.txt'; TransmitDS.HeaderContentType = 'text/xml; charset=utf-8'; TransmitDS.RequestCcsid = RXS_CCSID_UTF8; RXS_Transmit( gXmlResponse : gXmlRequest : TransmitDS ); endsr; begsr parse; RXS_ResetDS( ParseDS : RXS_DS_TYPE_PARSE ); ParseDS.GlobalHandler = %Paddr( XmlHandler ); RXS_Parse( gXmlResponse : ParseDS ); endsr; /end-free P XmlHandler B D XmlHandler PI D pType 10A Value D pXPath 1024A Value Varying D pData * Value D pDataLen 10I 0 Value D D parsed S Like(RXS_Var1Kv_t) /free if pXPath = '/Envelope/Body/FahrenheitToCelsiusResponse' + '/FahrenheitToCelsiusResult/'; // Calling RXS_STR in the V6R1-style forces you to use an // intermediate variable when you need to convert type to // integer or decimal. In V7R1-style, the below two lines of // code would be a single line that looks like this: // gCelsius = %Int( RXS_STR( pData : pDataLen ) ); RXS_STR( parsed : pData : pDataLen ); gCelsius = %Int( parsed ); endif; /end-free P E P Template B D PI D p Like(RXS_TEMPLATE_PARM) // Template RPG source was created from the actual template // STMF using the following command: // CRTRPGTPL STMF('/www/rxs/templates/geturi2.tpl') // FILE(RXS3/QRPGLETPL) MBR(CELSIUS) // The RPG Template source is copied from QRPGLETPL by using // /copy once in the D-specs and again below. /copy QRPGLETPL,CELSIUS P E ```