# RPG API Express 2.x Documentation --- # RPG-XML Suite 2.0x-2.8x System Requirements > Lists required IBM i features (SSL, Apache, QShell) and supported OS versions (5.4-7.6) for RPG-XML Suite 2.x. ## Installed Feature Requirements - If you need SSL functionality then cryptographic support needs to be installed on your IBM i. If you are on V5R4 or subsequent release then the SSL functionality already exists in the OS and doesn't need to be installed separately. The SSL license program for V5R3 and previous releases is 5722AC3. - RXS 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-XML Suite 2.0x-2.8x 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 - IBM i OS 5.4 / V5R4 --- # Installing RPG-XML Suite 2.0x-2.8x > Step-by-step installation guide covering save file transfer, library restoration, and Apache HTTP server configuration for RPG-XML Suite 2.x. 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 2.0x-2.8x > Upgrade procedures for single and multiple library RPG-XML Suite 2.x installations, including backup and upgrade command steps. 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 > Removes RPG-XML Suite 2.x by stopping Apache, deleting product libraries, removing IFS directories, and cleaning up license objects. 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. Remove the Apache server instance from OS/400: `RMVM FILE(QUSRSYS/QATMHINSTC) MBR(RXS)` 5. 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 > Lists RXS objects that must be excluded from system replication to prevent licensing errors. 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 > Instructions for transferring a RPG-XML Suite 2.x license to a different IBM i system, including required screenshots for support. 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_addHandler() > Registers a handler subprocedure for a specific XML element or attribute event before calling RXS_parse(). Call this subprocedure before [RXS_parse()](https://isupport.katointegrations.com/rxs/2.x/rxs_parse.md) to specify an event requiring notification. The event can be the beginning of an element, the content of an element, the end of an element or the attribute of an element. Example values for the pXPath parameter: - Example attribute XPath: "/PostAdr/name@title" - note the "@" before title. - Example element begin XPath: "/PostAdr/name>" - note the ">" at the end. - Example element content XPath: "/PostAdr/name/first/" - note the "/" at the end. - Example element end XPath: "/PostAdr/name/>" - note the "/>" at the end. Using RXS_addHandler() for a specific event (i.e. /PostAdr/name@title) in a program will generate an event to the handler you specify. If you also specified [RXS_allAttrHandler()](https://isupport.katointegrations.com/rxs/2.x/rxs_allattrhandler.md) so your program were notified of all attributes, you would be better off removing the [RXS_allAttrHandler()](https://isupport.katointegrations.com/rxs/2.x/rxs_allattrhandler.md) that was specific to /PostAdr/name@title as only one event will be generated and RXS_allAttrHandler would cover the /PostAdr/name@title event. It does not matter what the event type is -- RXS_ELEMBEGIN, RXS_ELEMCONTENT, RXS_ELEMEND, or RXS_ATTR -- if the program registers an "all handler" for that event type, the parser will send the event to that handler. ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Enables parsing of a specific event. D RXS_addHandler pr // The fully qualified path of the specified event. // Example: /PostAdr/name@title (attribute XPath) // Example: /PostAdr/name> (element begin XPath) // Example: /PostAdr/name/first/ (content XPath) // Example: /PostAdr/name/> (element end XPath) D pXPath like(RXS_XPath) value // The address of the local subprocedure in your program that should be // called when it encounters the XPath. This subprocedure must have the // prototype as shown in the example event handler. Use the %PADDR Built-In // Function to obtain the address of the local subprocedure (e.g. // %Paddr(myHandler)). D pHandler * procPtr value ``` --- # RXS_addLibLE() > Adds a library to the current job's library list. More often than not, your data files and business logic programs are not going to reside in the same library as your web service programs. RXS_addLibLE() allows you to easily add additional libraries to your library list. You can use [RXS_libLEExists()](https://isupport.katointegrations.com/rxs/2.x/rxs_libleexists.md) to see if a library list entry exists before adding the library to your library list: ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Adds the specified library to the beginning of your library list. D RXS_addLibLE pr // Required // The name of the library list entry to be added. D pLib 10a value ``` --- # RXS_allAttrHandler() > Registers a catch-all handler to receive every XML attribute event during parsing. Call this subprocedure before [RXS_parse()](https://isupport.katointegrations.com/rxs/2.x/rxs_parse.md) to tell the parser to notify a specific subprocedure of your program every time it encounters an XML attribute within an XML element (i.e. `I am the content` has an attribute named "example" with a value of "AttributeXYZ".) When the parser encounters an attribute, the specified handler will receive the value of the attribute (in this case "AttributeXYZ"). Note: Using this approach saves coding time compared to using [RXS_addHandler()](https://isupport.katointegrations.com/rxs/2.x/rxs_addhandler.md) when a program will retrieve a majority of the "attribute" events. ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Enables parsing of all XML attribute events. D RXS_allAttrHandler... D pr // The address of the local subprocedure in your program that should be // called when it encounters any attribute of any element. This // subprocedure must have the prototype as shown in the example event // handler. Use the %PADDR Built-In Function to obtain the address of the // local subprocedure (e.g. %Paddr(myHandler)). D pHandler * value procptr ``` --- # RXS_allElemBeginHandler() > Registers a catch-all handler to receive every XML element begin event during parsing. Call this subprocedure before [RXS_parse()](https://isupport.katointegrations.com/rxs/2.x/rxs_parse.md) to tell the parser to notify a specific subprocedure of your program every time it encounters the start of an element in a document (i.e. in the XML `I am the content` the `` is the start/begin). When the parser encounters an "element begin", it will call the handler specified in pHandler. Note: Using this approach saves coding time compared to using [RXS_addHandler()](https://isupport.katointegrations.com/rxs/2.x/rxs_addhandler.md) when a program will retrieve a majority of the "element begin" events. ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Enables parsing of all XML begin events. D RXS_allElemBeginHandler... D pr // The address of the local subprocedure in your program that should be // called when any element's begin tag is encountered. This subprocedure // must have the prototype as shown in the example event handler. Use the // %PADDR Built-In Function to obtain the address of the local subprocedure // (e.g. %Paddr(myHandler)). D pHandler * value procptr ``` --- # RXS_allElemContentHandler() > Registers a catch-all handler to receive every XML element content event during parsing. Call this subprocedure before [RXS_parse()](https://isupport.katointegrations.com/rxs/2.x/rxs_parse.md) to tell the parser to notify a specific subprocedure of your program every time it encounters content for an element in the document (i.e. in the XML `I am the content` the `I am the content` is the element context). When the parser encounters element content, it will send the content value to the handler specified in pHandler. Note: Using this approach saves coding time compared to using [RXS_addHandler()](https://isupport.katointegrations.com/rxs/2.x/rxs_addhandler.md) when a program will retrieve a majority of the "element content" events. ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Enables parsing of all XML content events. D RXS_allElemContentHandler... D pr // The address of the local subprocedure in your program that the parser // should call when it encounters any element's content. This subprocedure // must have the prototype as shown in the example event handler. Use the // %PADDR Built-In Function to obtain the address of the local subprocedure // (e.g. %PADDR(myHandler)). D pHandler * value procptr ``` --- # RXS_allElemEndHandler() > Registers a catch-all handler to receive every XML element end event during parsing. Call this subprocedure before [RXS_parse()](https://isupport.katointegrations.com/rxs/2.x/rxs_parse.md) to tell the parser to notify a specific subprocedure of your program every time it encounters the end of an element in a document (i.e. in the XML `I am the content` the `` is the end). When the parser encounters an "element end", it will call the handler specified in pHandler. Note: Using this approach saves coding time compared to using [RXS_addHandler()](https://isupport.katointegrations.com/rxs/2.x/rxs_addhandler.md) when a program will retrieve a majority of the "element end" events. ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Enables parsing of all XML end events. D RXS_allElemEndHandler... D pr // The address of the local subprocedure in your program that should be // called when any element's end tag is encountered. This subprocedure must // have the prototype as shown in the example event handler. Use the %PADDR // Built-In Function to obtain the address of the local subprocedure (e.g. // %Paddr(myHandler)). D pHandler * value procptr ``` --- # RXS_catchError() > Retrieves a programmer-defined error thrown by RXS_throwError() from within an ON-ERROR block. [RXS_throwError()](https://isupport.katointegrations.com/rxs/2.x/rxs_throwerror.md) and [RXS_catchError()](https://isupport.katointegrations.com/rxs/2.x/rxs_catcherror.md) are used as an extension to the RPG compiler's MONITOR op-code. When IBM added the MONITOR op-code they only allowed for compiler predefined error messages to be "caught" on the corresponding ON-ERROR statement. That means you can't have an ON-ERROR statement watching for a programmer defined error code. With just a little bit of additional code we can utilize the MONITOR and ON-ERROR clauses to our benefit. By surrounding a piece of code that could be erroneous with the MONITOR op-code we can use the ON-ERROR clause to catch any errors that are thrown by programs further down the program call stack, and then using [RXS_catchError()](https://isupport.katointegrations.com/rxs/2.x/rxs_catcherror.md) to retrieve the most recent error off of the program call stack. For example, if PGMA wraps a MONITOR around a call to PGMB and PGMB uses [RXS_throwError()](https://isupport.katointegrations.com/rxs/2.x/rxs_throwerror.md) to generate an error, then the next line of code executed will be the ON-ERROR clause in PGMA because the RPG runtime recognizes that an error occurred and it looks for it's next stopping point (ON-ERROR is one such stopping point). RXS_catchError can then be used within the ON-ERROR clause to retrieve the last error off of the program call stack. At that point PGMA has access to the error code, severity, program name and error text. The decision of how to continue is up to PGMA as it caught the error and avoided an abnormal end. This is similar to using a *PSSR subroutine except that with *PSSR your program doesn't regain control after the *PSSR sub routine executes. See the program ERR1 for more details on how to use this API. ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Used to catch an error returned to the ON-ERROR clause of a MONITOR // block. Error data will be returned as a data structure matching // RXS_Error. D RXS_catchError pr likeds(RXS_Error) D extproc('ERROR_CATCH') ``` --- # RXS_charToBln() > Converts XML boolean string values (true/false, 1/0, on/off) to an RPG indicator. Use RXS_charToBln() to easily convert a character Boolean value (i.e. true/false, t/f, on/off/, 1/0) to an RPG Boolean. This will save the headache of programming for all of the different Boolean formats out there. Note that according to the XML specification that the valid Boolean values are **true** and **false**. If the value in pValFrmXml matches the value in pTrueVal then *on will be returned. If the value in pValFrmXml matches the value in pFalseVal then *off will be returned. If the value in pValFrmXml doesn't match either pTrueVal or pFalseVal then the value specified in pDftVal will be returned. Typical usage would look like: `myBlnVar = RXS_charToBln(strBln: 'true': 'false': *off);` ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Returns *On if the value being tested is considered true, *Off if it is // considered false. D RXS_charToBln pr n // Required // The string value parsed from an XML document. Letters will be converted // to lowercase before processing. // Example: true,False,T,f,1,0 D pValFrmXml 10a value // Required // The value which, if passed in pValFrmXml, would represent a true Boolean // condition. Must be lowercase. // Example: t,1 D pTrueVal 10a value // Required // The value which, if passed in pValFrmXml, would represent a false // Boolean condition. Must be lowercase. // Example: f,false D pFalseVal 10a value // Required // Default, fallback value which will be returned if the character data in // pValFrmXml does not match either of the specified true or false values. D pDftVal n value ``` --- # RXS_charToNbr() > Converts a character string from XML to a numeric or packed-decimal value. XML data is passed as strings. If your system needs to store it as decimal or numeric data, you will need to convert it. This provides an alternative to the %Dec and %Int built-in functions. Typical usage would look like: `CM.CUSTNBR = RXS_charToNbr(pData: 0);` ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Convers a character string into a numeric value. D RXS_charToNbr pr 30P 9 // Required // The character data to be converted. If the process encounters a // non-numeric character (excluding decimal points), conversion will halt // and the subprocedure will return the converted value to that point. D pStr 50A varying const // Required // A default value to be used in the event that the character data being // passed cannot be converted. // Example: 0 D pDft 30P 9 value ``` --- # RXS_charToTimestamp() > Converts an XML timestamp string to an IBM i timestamp value using a customizable format pattern. Use RXS_charToTimestamp() to easily convert a timestamp coming from an XML document (i.e. string representation of a timestamp) to a valid IBM i/RPG timestamp format. This will save the headache of programming for all of the different timestamp formats out there and doing a bunch of sub-stringing and concatenation. Valid keywords for pFormat are listed below: - yyyy = Year - MM = Month - dd = Day - hh = Hour - mm = Minute - ss = Second - SS = Millisecond Typical usage would look like: `RXS_charToTimestamp(strTimestamp: 'yyyy-MM-dd-hh.mm.ss.SSSSSS': %Timestamp());` ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Converts a character string to a timestamp value. D RXS_charToTimestamp... D pr z // Required // Character string date/time data which is to be converted to a timestamp. // Example: 2016-04-21-13.12.24 D pString 30a value // Required // The format of the date/time character string. // Example: yyyy-MM-dd-hh.mm.ss D pFormat 30a value // Required // Default, fallback return value that will be returned if the subprocedure // cannot process the character string passed in the first parameter. // Example: %timestamp() D pDft z value ``` --- # RXS_cmpTransFile() > Builds a unique IFS file path by combining the transaction directory, separators, a unique sequence number, and a file extension. In the process of doing web services you will most likely run across the need to create many files in the IFS, and each of those files must be uniquely named if you don't want one to over write the next. Instead of doing several concatenations of strings and dates and numbers to come up with a unique file name, use RXS_cmpTransFile(). Basically, a programmer tells the function the file extension (i.e. .xml), the separator for each piece of information in the file name (up to 4) that will be passed to it (i.e. _). Typical usage would look like: `gReqFile = RXS_cmpTransFile('_': '.xml': RXS_UnqNbr : 'req');` This produces a string with the contents /www/myrxs/trans/99999_req.xml where 99999 is the next sequential number in data queue RXS/RXSUNQ, and '/www/myrxs/trans/' is the value stored in column TRANSDIR in table RXSCFG. ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Creates a unique IFS file path. D RXS_cmpTransFile... D pr like(RXS_FilePath) // Required // The value to be used as the separator between each of the file path // components passed in pVal1-5. D pSep 1a value // Required // The extension of the file path to be generated, including the period. // Example: .xml D pExt 10a value varying // Required // Character data to be used in building the unique file path. Can accept // character data, or either RXS_UnqNbr() or RXS_Timestamp(). D pVal1 value like(RXS_NameVal) D options(*nopass) // Character data to be used in building the second segment of the unique // file path. Can accept character data, or either RXS_UnqNbr() or // RXS_Timestamp(). D pVal2 value like(RXS_NameVal) D options(*nopass) // Character data to be used in building the third segment of the unique // file path. Can accept character data, or either RXS_UnqNbr() or // RXS_Timestamp(). D pVal3 value like(RXS_NameVal) D options(*nopass) // Character data to be used in building the fourth segment of the unique // file path. Can accept character data, or either RXS_UnqNbr() or // RXS_Timestamp(). D pVal4 value like(RXS_NameVal) D options(*nopass) // Character data to be used in building the fifth segment of the unique // file path. Can accept character data, or either RXS_UnqNbr() or // RXS_Timestamp(). D pVal5 value like(RXS_NameVal) D options(*nopass) ``` --- # RXS_deleteFile() > Deletes a file from the IFS. Allows the programmer to easily delete a file in the IFS. ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Deletes the specified IFS file. D RXS_deleteFile pr 10i 0 // The qualified name of the IFS file to be deleted. // Example: /myFolder/myFile.xml D pFile value like(RXS_FilePath) ``` --- # RXS_DOMBuild() > Builds an in-memory DOM tree from an XML document for random-access parsing (higher memory use than the event-based parser). **NOTE:** The RXS_DOM* APIs were created to allow for a different approach to parsing XML documents. Depending on the complexity of your XML and what data elements you are parsing, the RXS_DOM* APIs can make the syntax for parsing simpler. The simpler syntax comes with a cost because the entire XML document is parsed and stored in memory so you can access any element data at any time (think of it as being able to "CHAIN" to the XML structure - random access). Performance for smaller XML files is comparable for the two XML parsers within RPG-XML Suite, but the larger the XML file the bigger the divide. For example, a large 4MB XML file will take 200 seconds with the event based parser and 600 seconds with the DOM parser. So make sure to factor that into your decision on whether to use the RXS_DOM* APIs to parse or the event based parser. The following rules apply when specifying non-blank values for either pStartXPath or pEndXPath: - If pStartXPath is specified as non-blank, although the entire document will be parsed, the building of the DOM will only start when the first instance of that XPath is found. - If pEndXPath is specified as non-blank and pStartXPath is specified as blank, parsing will stop when the first instance of pEndXPath path is found. - If pStartXPath is specified as non-blank and pEndXPath is also specified as non-blank, DOM building will start when the first instance of the pStartXPath is found and will stop when the first subsequent instance of pEndXPath is found. - If pStartXPath is specified as non-blank but pEndXPath is not specified (or is specified as blank), DOM building will start when the first instance of the gStartXPath is found (same as rule 1 above) and will stop when that XML 'section' has ended. ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Builds a DOM tree from XML. D RXS_DOMBuild pr // Used to specify a file in the IFS or actual XML residing in an RPG // variable. If an IFS file is specified it must either be fully qualified // (i.e. /home/user/mydoc.xml) or must reside in the default transaction // directory (i.e. /www/rxs/trans.) If it resides in the default // transaction directory then you can just specify it as 'mydoc.xml.' D pFilePathOrData... D value like(RXS_XmlData) // Use RXS_STMF if the value passed in pFilePathOrData is a path to an IFS // file. Use RXS_VAR if the value passed in pFilePathOrData contains XML. // Valid values: RXS_STMF, RXS_VAR D pType value like(RXS_Type) // A structure which can be used to trap for errors on return from // RXS_DOMBuild(). D pError likeds(RXS_Error) // An optional integer which can contain various options used by // RXS_DOMBuild(). See the documentation for the RXS_DOMSetOpt() procedure // for details of the various allows options. Passing this parameter // directly to RXS_DOMBuild() is the same as performing a separate call to // RXS_DOMSetOpt() prior to calling RXS_DOMBuild(). D pOptions 10i 0 value options(*nopass) // An optional path specifying the XPath within the DOM where parsing // should start. D pStartXPath value like(RXS_XPath) D options(*nopass) // An optional path specifying the XPath within the DOM where parsing // should stop. D pEndXPath value like(RXS_XPath) D options(*nopass) ``` --- # RXS_DOMCleanup() > Frees memory allocated by RXS_DOMBuild() after DOM parsing is complete. **NOTE:** The RXS_DOM* APIs were created to allow for a different approach to parsing XML documents. Depending on the complexity of your XML and what data elements you are parsing, the RXS_DOM* APIs can make the syntax for parsing simpler. The simpler syntax comes with a cost because the entire XML document is parsed and stored in memory so you can access any element data at any time (think of it as being able to "CHAIN" to the XML structure - random access). Performance for smaller XML files is comparable for the two XML parsers within RPG-XML Suite, but the larger the XML file the bigger the divide. For example, a large 4MB XML file will take 200 seconds with the event based parser and 600 seconds with the DOM parser. So make sure to factor that into your decision on whether to use the RXS_DOM* APIs to parse or the event based parser. Call this subprocedure to clean up any memory associated with DOM parsing operations. This procedure should be called after all DOM-related processing has finished. If it is not called, memory associated with DOM parsing will be freed when the job ends. ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Cleans up any memory associated with DOM parsing operations. If this is // not called, memory associated with DOM parsing will be freed when the // job ends. D RXS_DOMcleanup pr ``` --- # RXS_DOMGetData() > Retrieves element or attribute values from a DOM tree built with RXS_DOMBuild() using an XPath-style locator. **NOTE:** The RXS_DOM* APIs were created to allow for a different approach to parsing XML documents. Depending on the complexity of your XML and what data elements you are parsing, the RXS_DOM* APIs can make the syntax for parsing simpler. The simpler syntax comes with a cost because the entire XML document is parsed and stored in memory so you can access any element data at any time (think of it as being able to "CHAIN" to the XML structure - random access). Performance for smaller XML files is comparable for the two XML parsers within RPG-XML Suite, but the larger the XML file the bigger the divide. For example, a large 4MB XML file will take 200 seconds with the event based parser and 600 seconds with the DOM parser. So make sure to factor that into your decision on whether to use the RXS_DOM* APIs to parse or the event based parser. Call this subprocedure after a call to [RXS_DOMBuild()](https://isupport.katointegrations.com/rxs/2.x/rxs_dombuild.md) to retrieve the value of an XML element or attribute. **Note:** Only the first parameter (pXPath1) is required. If more than one parameter is specified, the following rules apply: - If the last XPath parameter specified includes an attribute, it must be the last parameter. - If the last XPath parameter specified does NOT include an attribute AND it is the last parameter, the DOM Parser will assume that the first instance of that XPath is intended. ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Retrieves data elements from a specific XPath. Returns the contents of // the element specified and parsed out of the provided XML. If the last // XPath parameter includes an attribute, it must be the last parameter. If // the last XPath parameter does not include an attribute and it is the // last parameter, the DOM parser will assume that the first instance of // that XPath is intended. D RXS_DOMGetData pr like(RXS_XmlData) // Required // An XPath segment value. D pXPath1 const like(RXS_XPath) // Required // An integer indicating the instance of the specified XPath segment. D pInstance1 10i 0 const options(*nopass) // An XPath segment value. D pXPath2 const like(RXS_XPath) D options(*nopass) // An integer indicating the instance of the specified XPath segment. D pInstance2 10i 0 const options(*nopass) // An XPath segment value. D pXPath3 const like(RXS_XPath) D options(*nopass) // An integer indicating the instance of the specified XPath segment. D pInstance3 10i 0 const options(*nopass) // An XPath segment value. D pXPath4 const like(RXS_XPath) D options(*nopass) // An integer indicating the instance of the specified XPath segment. D pInstance4 10i 0 const options(*nopass) // An XPath segment value. D pXPath5 const like(RXS_XPath) D options(*nopass) // An integer indicating the instance of the specified XPath segment. D pInstance5 10i 0 const options(*nopass) // An XPath segment value. D pXPath6 const like(RXS_XPath) D options(*nopass) // An integer indicating the instance of the specified XPath segment. D pInstance6 10i 0 const options(*nopass) // An XPath segment value. D pXPath7 const like(RXS_XPath) D options(*nopass) // An integer indicating the instance of the specified XPath segment. D pInstance7 10i 0 const options(*nopass) // An XPath segment value. D pXPath8 const like(RXS_XPath) D options(*nopass) // An integer indicating the instance of the specified XPath segment. D pInstance8 10i 0 const options(*nopass) // An XPath segment value. D pXPath9 const like(RXS_XPath) D options(*nopass) // An integer indicating the instance of the specified XPath segment. D pInstance9 10i 0 const options(*nopass) // An XPath segment value. D pXPath10 const like(RXS_XPath) D options(*nopass) // An integer indicating the instance of the specified XPath segment. D pInstance10 10i 0 const options(*nopass) // An XPath segment value. D pXPath11 const like(RXS_XPath) D options(*nopass) // An integer indicating the instance of the specified XPath segment. D pInstance11 10i 0 const options(*nopass) // An XPath segment value. D pXPath12 const like(RXS_XPath) D options(*nopass) // An integer indicating the instance of the specified XPath segment. D pInstance12 10i 0 const options(*nopass) // An XPath segment value. D pXPath13 const like(RXS_XPath) D options(*nopass) // An integer indicating the instance of the specified XPath segment. D pInstance13 10i 0 const options(*nopass) // An XPath segment value. D pXPath14 const like(RXS_XPath) D options(*nopass) // An integer indicating the instance of the specified XPath segment. D pInstance14 10i 0 const options(*nopass) // An XPath segment value. D pXPath15 const like(RXS_XPath) D options(*nopass) // An integer indicating the instance of the specified XPath segment. D pInstance15 10i 0 const options(*nopass) // An XPath segment value. D pXPath16 const like(RXS_XPath) D options(*nopass) // An integer indicating the instance of the specified XPath segment. D pInstance16 10i 0 const options(*nopass) // An XPath segment value. D pXPath17 const like(RXS_XPath) D options(*nopass) // An integer indicating the instance of the specified XPath segment. D pInstance17 10i 0 const options(*nopass) // An XPath segment value. D pXPath18 const like(RXS_XPath) D options(*nopass) // An integer indicating the instance of the specified XPath segment. D pInstance18 10i 0 const options(*nopass) // An XPath segment value. D pXPath19 const like(RXS_XPath) D options(*nopass) // An integer indicating the instance of the specified XPath segment. D pInstance19 10i 0 const options(*nopass) // An XPath segment value. D pXPath20 const like(RXS_XPath) D options(*nopass) // An integer indicating the instance of the specified XPath segment. D pInstance20 10i 0 const options(*nopass) ``` --- # RXS_DOMGetDataCount() > Returns the count of a specified element in a DOM tree. **NOTE:** The RXS_DOM* APIs were created to allow for a different approach to parsing XML documents. Depending on the complexity of your XML and what data elements you are parsing, the RXS_DOM* APIs can make the syntax for parsing simpler. The simpler syntax comes with a cost because the entire XML document is parsed and stored in memory so you can access any element data at any time (think of it as being able to "CHAIN" to the XML structure - random access). Performance for smaller XML files is comparable for the two XML parsers within RPG-XML Suite, but the larger the XML file the bigger the divide. For example, a large 4MB XML file will take 200 seconds with the event based parser and 600 seconds with the DOM parser. So make sure to factor that into your decision on whether to use the RXS_DOM* APIs to parse or the event based parser. Call this subprocedure after a call to [RXS_DOMBuild()](https://isupport.katointegrations.com/rxs/2.x/rxs_dombuild.md) to retrieve the quantity of specified elements.. **Note:** Only the first parameter (pXPath1) is required. If more than one parameter is specified, the following rules apply: - If the last XPath parameter specified includes an attribute, it must be the last parameter. - If the last XPath parameter specified does NOT include an attribute AND it is the last parameter, the DOM Parser will assume that the first instance of that XPath is intended. ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Retrieves the count of data elements from a specific XPath. If the last // XPath parameter includes an attribute, it must be the last parameter. If // the last XPath parameter does not include an attribute and it is the // last parameter, the DOM parser will assume that the first instance of // that XPath is intended. D RXS_DOMGetDataCount... D pr 10i 0 // Required // An XPath segment value. D pXPath1 const like(RXS_XPath) // Required // An integer indicating the instance of the specified XPath segment. D pInstance1 10i 0 const options(*nopass) // An XPath segment value. D pXPath2 const like(RXS_XPath) D options(*nopass) // An integer indicating the instance of the specified XPath segment. D pInstance2 10i 0 const options(*nopass) // An XPath segment value. D pXPath3 const like(RXS_XPath) D options(*nopass) // An integer indicating the instance of the specified XPath segment. D pInstance3 10i 0 const options(*nopass) // An XPath segment value. D pXPath4 const like(RXS_XPath) D options(*nopass) // An integer indicating the instance of the specified XPath segment. D pInstance4 10i 0 const options(*nopass) // An XPath segment value. D pXPath5 const like(RXS_XPath) D options(*nopass) // An integer indicating the instance of the specified XPath segment. D pInstance5 10i 0 const options(*nopass) // An XPath segment value. D pXPath6 const like(RXS_XPath) D options(*nopass) // An integer indicating the instance of the specified XPath segment. D pInstance6 10i 0 const options(*nopass) // An XPath segment value. D pXPath7 const like(RXS_XPath) D options(*nopass) // An integer indicating the instance of the specified XPath segment. D pInstance7 10i 0 const options(*nopass) // An XPath segment value. D pXPath8 const like(RXS_XPath) D options(*nopass) // An integer indicating the instance of the specified XPath segment. D pInstance8 10i 0 const options(*nopass) // An XPath segment value. D pXPath9 const like(RXS_XPath) D options(*nopass) // An integer indicating the instance of the specified XPath segment. D pInstance9 10i 0 const options(*nopass) // An XPath segment value. D pXPath10 const like(RXS_XPath) D options(*nopass) // An integer indicating the instance of the specified XPath segment. D pInstance10 10i 0 const options(*nopass) // An XPath segment value. D pXPath11 const like(RXS_XPath) D options(*nopass) // An integer indicating the instance of the specified XPath segment. D pInstance11 10i 0 const options(*nopass) // An XPath segment value. D pXPath12 const like(RXS_XPath) D options(*nopass) // An integer indicating the instance of the specified XPath segment. D pInstance12 10i 0 const options(*nopass) // An XPath segment value. D pXPath13 const like(RXS_XPath) D options(*nopass) // An integer indicating the instance of the specified XPath segment. D pInstance13 10i 0 const options(*nopass) // An XPath segment value. D pXPath14 const like(RXS_XPath) D options(*nopass) // An integer indicating the instance of the specified XPath segment. D pInstance14 10i 0 const options(*nopass) // An XPath segment value. D pXPath15 const like(RXS_XPath) D options(*nopass) // An integer indicating the instance of the specified XPath segment. D pInstance15 10i 0 const options(*nopass) // An XPath segment value. D pXPath16 const like(RXS_XPath) D options(*nopass) // An integer indicating the instance of the specified XPath segment. D pInstance16 10i 0 const options(*nopass) // An XPath segment value. D pXPath17 const like(RXS_XPath) D options(*nopass) // An integer indicating the instance of the specified XPath segment. D pInstance17 10i 0 const options(*nopass) // An XPath segment value. D pXPath18 const like(RXS_XPath) D options(*nopass) // An integer indicating the instance of the specified XPath segment. D pInstance18 10i 0 const options(*nopass) // An XPath segment value. D pXPath19 const like(RXS_XPath) D options(*nopass) // An integer indicating the instance of the specified XPath segment. D pInstance19 10i 0 const options(*nopass) // An XPath segment value. D pXPath20 const like(RXS_XPath) D options(*nopass) // An integer indicating the instance of the specified XPath segment. D pInstance20 10i 0 const options(*nopass) ``` --- # RXS_DOMSetOpt() > Configures DOM parsing options (whitespace handling, case sensitivity, trimming, mixed content) before calling RXS_DOMBuild(). **NOTE:** The RXS_DOM* APIs were created to allow for a different approach to parsing XML documents. Depending on the complexity of your XML and what data elements you are parsing, the RXS_DOM* APIs can make the syntax for parsing simpler. The simpler syntax comes with a cost because the entire XML document is parsed and stored in memory so you can access any element data at any time (think of it as being able to "CHAIN" to the XML structure - random access). Performance for smaller XML files is comparable for the two XML parsers within RPG-XML Suite, but the larger the XML file the bigger the divide. For example, a large 4MB XML file will take 200 seconds with the event based parser and 600 seconds with the DOM parser. So make sure to factor that into your decision on whether to use the RXS_DOM* APIs to parse or the event based parser. Call this subprocedure prior to calling [RXS_DOMBuild()](https://isupport.katointegrations.com/rxs/2.x/rxs_dombuild.md), to specify options to be used by the DOM Parser. The options are as follows: `DOM_IGNWS` : Introduced in v2.4. If specified, the DOM Parser will ignore whitespace-only elements. (The default behavior is to process whitespace-only elements.) Using this option can improve performance significantly in very large XML documents where many empty elements exist. `DOM_IGNCASE` : If specified, the DOM Parser will ignore case-differences. `DOM_NOTRIM` : If specified, the DOM Parser will not trim leading and trailing blanks from XML element values (by default, leading and trailing blanks are trimmed from XML element values). `DOM_MIXED` : If specified, denotes to the DOM Parser that the XML contains mixed content. Note that if the XML contains mixed content and DOM_MIXED is not specified, incorrect results may be returned from subsequent DOM-related procedures. Note also that specifying DOM_MIXED may result in RXS_DOMBuild taking longer than if DOM_MIXED is not specified. `DOM_ALTSEARCH` : If specified, an alternate search criteria will be used by the DOM Parser during the data search/replace phase. This value may be specified to improve performance when parsing very large XML documents. Whether it improves the performance depends on the XML element value data, and so there is no guarantee that specifying it will improve parsing performance. `DOM_NOIGNWS` : Deprecated. This API can be called with multiple options added together, e.g.: `RXS_DOMSetOpt( DOM_IGNCASE + DOM_NOTRIM + DOM_ALTSEARCH );` ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Used to set options to control DOM parsing. This API can be called with // multiple options added together to act as one parameter. // Example: RXS_DOMSetOpt( DOM_IGNCASE + DOM_NOTRIM + DOM_ALTSEARCH ); D RXS_DOMsetOpt pr // An integer which consists of a sum of the various available options. // Valid values: DOM_IGNWS (ignore whitespace-only elements), DOM_IGNCASE // (ignore case-differences), DOM_NOTRIM (will not trim leading and // training blanks from XML element values), DOM_MIXED (denotes to the DOM // parser that the XML contains mixed content), DOM_ALTSEARCH (alternate // search criteria will be used by the DOM parser during the data // search/replace stage), DOM_NOIGNWS (deprecated) D pOpt 10i 0 const ``` --- # RXS_getBuffData() > Returns buffered Template Engine output as a character variable for use with RXS_getUri(). Use this subprocedure to retrieve the data that has buffered in the Template Engine. Note that RXS_VAR should have been specified for the pOutType parameter on the call to [RXS_initTplEng()](https://isupport.katointegrations.com/rxs/2.x/RXS_initTplEng.md) API for this to work. This is most often used in conjunction with [RXS_getUri()](https://isupport.katointegrations.com/rxs/2.x/RXS_getUri.md) and passed for the pReqData parameter. ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Retrieves the composition engine buffer and stores it in a field, which // will then be returned to the calling program. D RXS_getBuffData... D pr like(RXS_XmlData) // Determine whether or not to flush the buffer after the template data is // returned. This value should most often be *On. D pFlushBuff n const options(*nopass) // Used to tell the template engine where to start retrieving data in the // template engine buffer. Unless necessity dictates it be used do not pass // this parameter (note the *NOPASS). Use RXS_getBuffLen() to determine if // there is more than 65535 bytes of data currently buffered in the // template engine. D pOffset 10u 0 const options(*nopass) ``` --- # RXS_getBuffLen() > Returns the byte length of data currently buffered by the Template Engine. Use this subprocedure to retrieve the length of data that has buffered in the Template Engine. Note that RXS_VAR should have been specified for the pOutType parameter on the call to [RXS_initTplEng()](https://isupport.katointegrations.com/rxs/2.x/RXS_initTplEng.md) API for this to work. This is most often used in conjunction with [RXS_getUri()](https://isupport.katointegrations.com/rxs/2.x/RXS_getUri.md) where RXS_getBuffData() is used to obtain the current data stored in the template engine. ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Returns the length, in bytes, of the current composition engine buffer. D RXS_getBuffLen... D pr 10u 0 ``` --- # RXS_getEnvVar() > Retrieves Apache environment variables and HTTP request headers from the current CGI job. There are times when you may need to gain access to the Apache server's environment variables or HTTP headers that are sent with the incoming request. This subprocedure will ease that retrieval. Some of the valid values to pass into RXS_getEnvVar include the following: - 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 ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Get an Apache environment variable or incoming HTTP header. D RXS_getEnvVar... D pr 32767a varying // The name of the environment variable from which to retrieve the value. // Example: AUTH_TYPE,CONTENT_TYPE,PATH_INFO,REMOTE_ADDR,SERVER_PORT D pEnvVar 30a value ``` --- # RXS_getFileSize() > Returns the size in bytes of an IFS file. This subprocedure will allow the programmer to obtain the size of a file in the IFS in bytes. ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Retrieves the size of the specified IFS file, in bytes, as an integer. D RXS_getFileSize... D pr 10i 0 // The qualified name of the IFS file which is being queried. // Example: /myFolder/myFile.xml D pFile value like(RXS_FilePath) ``` --- # RXS_getTplDir() > Returns the currently active template directory path. Returns the value specified for the template directory that was either specified on the call to [RXS_initTplEng()](https://isupport.katointegrations.com/rxs/2.x/rxs_inittpleng.md) or [RXS_setTplDir()](https://isupport.katointegrations.com/rxs/2.x/rxs_settpldir.md) or was obtained by default from the RXSCFG file. ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Retrieves the IFS path of the currently configured template directory D RXS_getTplDir... D pr like(RXS_FilePath) ``` --- # RXS_getTransDir() > Returns the currently active transaction directory path. Returns the value specified for the transaction directory that was either specified on the call to [RXS_initTplEng()](https://isupport.katointegrations.com/rxs/2.x/rxs_inittpleng.md) or [RXS_setTplDir()](https://isupport.katointegrations.com/rxs/2.x/rxs_settpldir.md) or was obtained by default from the RXSCFG file. ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Retrieves the IFS path of the currently configured transaction directory D RXS_getTransDir... D pr like(RXS_FilePath) ``` --- # RXS_getUri() > Sends an XML payload to a remote HTTP/HTTPS endpoint and returns the response; the primary web service call subprocedure in RPG-XML Suite 2.x. Call this subprocedure to send an XML stream to an "end point". An "end point" describes a web service you call or "consume". Program GETURI3 provides an example of calling end point RXS3 which resides on your IBM i from the initial install of RPG-XML Suite. The RXS_getURI API is VERY configurable concerning what can be sent to the remote server. When doing standard web services there are only a handful of values for the pInCfg data structure that need to be filled which is detailed by way of the examples in RXS/EXAMPLE. ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Sends an XML stream to an end point for the web service you are calling // or consuming. D RXS_getUri pr // Required // This parameter allows you to describe the communication that will happen // with the server on the other end of the line. The data structure is // broken out below by field with a definition. D pInCfg likeds(RXS_GetUriIn) // This parameter should be specified if you are not using an IFS file to // hold your XML request but instead have it in an RPG variable. To get // your XML into an RPG variable you would have specified RXS_VAR as the // pOutType on RXS_initTplEng() and then used RXS_getBuffData(). Note that // a max of 65535 bytes can be sent using this method. If more XML is to be // sent then an IFS file should be used. If an IFS file is used you can use // *OMIT to omit this parameter. D pReqData like(RXS_XMLData) options(*omit) // This parameter should be specified if you are not using an IFS file to // hold your XML response but instead wish to have it placed in an RPG // variable. Note that RPG-XML Suite can parse XML that resides in either // an RPG variable or an IFS file. Note that a max of 65535 bytes can be // received using this method. If more XML is to be received then an IFS // file should be used. If an IFS file is used you can use *OMIT to omit // this parameter. D pRspData like(RXS_XMLData) options(*omit) // This parameter will receive back the raw HTTP response headers which can // be used for debugging purposes. *OMIT can be specified if you do not // wish to receive back the HTTP response headers. D pHttpHdr like(RXS_XMLData) options(*omit) D pErr likeds(RXS_Error) options(*nopass) ``` ## Data Structures ### RXS_GetUriIn ```rpgle D RXS_getUriIn ds qualified inz // Enter the URI to be used. Do not include any data (GET or POST) // parameters or port in this field. Use pInCfg.port to specify a specific // port. // Example: http://www.myserver.com/apps/getcustomer.asp D URI 256 // Specify the output type to be used. When using the RXS_getUri to return // a value to your application, set this value to RXS_VAR. To return the // data to a physical file, use RXS_PHY_FILE. To return the data to a // stream file, set the value to RXS_STMF. If you intend to parse the data // using RXS_parse, use RXS_VAR or RXS_STMF. The parser does not parse XML // stored in a physical file. // Valid values: RXS_VAR, RXS_PHY_FILE, RXS_STMF // Default: RXS_VAR D RspType 10 // Enter the user agent that you wish to be used for the request. This // parameter may or may not have an effect on the success of the request. // The default value previous to v2.70 was "Mozilla/4.0 (compatible; MSIE // 5.5; Windows 98)". // Default: KrengelTech HTTP Client D UserAgent 128 // Specify constant RXS_STMF to have the XML request pulled from a file in // the IFS or RXS_VAR if you are passing the XML in via an RPG variable // through RXS_getURI parameter pReqData. // Valid values: RXS_STMF, RXS_VAR // Default: RXS_VAR D ReqType 2048 // If RXS_STMF was specified on the ReqType parameter then specify the // fully qualified path of the stream file containing the XML. If it // resides in the default transaction directory, just specify it as // 'mydoc.xml'. D ReqStmf 256 // Specify the IP address or DNS-resolvable name of a proxy server if // required. D Proxy 128 // Enter the port number used to make the request. If using a proxy server, // pass the proxy server port. In this case, if you make a URI request from // a server on a port other than 80, that port must be specified in the URI // request. For example, www.myserver.com:442 // Default: 80 D Port 10i 0 // Specify the request method used for the web service request. // Valid values: RXS_GET, RXS_POST // Default: RXS_POST D ReqMeth 10 // Specify the type of data that you will accept. This value should be in a // valid content-type form. The default value previous to v2.70 was // "text/html". // Default: text/xml D Accept 128 // Specify the host name that will be sent with the request. The default // will be set to the host on the domain used in the request. // Default: localhost D Host 64 // Specify any cookie data to be sent with this request. Further // instructions for formatting this data is available at RFC2109. D Cookie 4096 // Specify the value to be used as the referrer for this request. D Referer 128 // Specify a value to be sent with the Connection HTTP header. // Example: keep-alive D Connection 128 // Specify the content type of the request. // Default: text/xml D ContType 128 // Specify the protocol being used. // Example: HTTP D Proto 20 // Specify the protocol version being used. // Example: Version 1.0 D HTTPVer 10 // Specify the number of user defined generic headers to be used. D NbrHdrs 10i 0 // Specify the user defined generic headers to be used in this array. D UsrHdr 32 dim(50) // Specify the user defined generic header data to be used in this array. // Each element should relate to a header in the RXS_getUriIn.UsrHdr array. D UsrHdrDta 128 dim(50) // Specify the library and physical file to be used to store the data // results if RXS_PHY_FILE was specified on the RXS_getUriIn.RspType // parameter. The first ten characters should be the file name and the // second ten characters should contain the library name. This should be // used infrequently. D File 20 // Specify the name of the physical file member to store the data results // if RXS_PHY_FILE was specified on the RXS_getUriIn.RspType parameter. // This should be used infrequently. D Mbr 10 // Specify the fully qualified path of the stream file to store the data // results if RXS_STMF was specified on the RXS_getUriIn.RspType parameter. // If it resides in the default transaction directory, just specify it as // 'mydoc.xml.' D RspStmf 128 // Specify RXS_YES on this parameter if you are simulating an HTML file // upload web page. Note that this does not refer to the XML document being // sent but a separate file. This should be used infrequently. D UpFile 4 // Specify the fully qualified location of the stream file that will be // uploaded if RXS_STMF (RXS_YES?) was specified for the // RXS_getUriIn.UpFile parameter. Note that this does not refer to the XML // document being sent but a separate file. This should be used // infrequently. D UpStmf 128 // Specifies the name of the file as the server will see it. This value // defaults to the file name specified on RXS_getUriIn.UpStmf. Note that // this does not refer to the XML document being sent but a separate file. // This should be used infrequently. D UpName 128 // When specifying RXS_YES for the RXS_getUriIn.UpFile parameter, name the // form field from the upload page that is being simulated. Note that this // does not refer to the XML document being sent, but a separate file. This // should be used infrequently. D UpField 64 // When specifying RXS_YES for the RXS_getUriIn.UpFile parameter, specify // the content-type of the file being uploaded. Note that this does not // refer to the XML document being sent but a separate file. This should be // used infrequently. D UpCont 64 // Specify the user ID for this parameter if Basic Authentication is used // on this request. D BUser 64 // Specify the password for this parameter if Basic Authentication is used // on this request. D BPW 64 // If using a proxy on this request that requires a user id and password, // specify the proxy user id on this parameter. D PUser 64 // If using a proxy on this request that requires a user id and password, // specify the proxy password on this parameter. D PPW 64 // Specify RXS_YES on this parameter if a Secure Sockets Layer (SSL) // request is being made. D SSL 4 // Used to assign an application ID for RXS_getUri. // Default: none D SSLApp 64 // Specify the certificate store to use with the SSL request. This value // defaults to RXS_SYSTEM which uses the system certificate store. If you // wish to use another certificate store, specify the qualified location of // the store. // Default: RXS_SYSTEM D CStore 128 // Specify the certificate store password, if applicable. D CPW 64 // Specify a value in seconds to cause a timeout during an SSL handshake. A // value of RXS_NONE will specify no timeout value. // Default: RXS_NONE D SSLTime 10i 0 // Specify a value in seconds for a timeout on the request. // Default: 30 D Timeout 10i 0 // Specify a code page to be used when creating stream files. // Default: 819 D CodPag 10i 0 // Specify whether or not to close the connection after the request has // completed. Leaving the connection open may increase performance with // multiple calls to the same server. // Default: RXS_YES D Close 4 // Specify RXS_YES to debug the request that was made. A file will be // created in the IFS named /tmp/getUridebug.txt which includes the actual // request that was made with the RXS_getUri call. You can override this // value by specifying a different file in RXS_getUriIn.DebugFile. D Debug 4 // Specify the location of a file to place debug information to override // the default of /tmp/getUridebug.txt. D DebugFile 256 // Specify the CCSID to use for EBCDIC to ASCII and ASCII to EBCDIC // translations. This parameter will override the tables if specified. If // the tables are used instead of the CCSID for translations, specify 0 // (zero) for this value. D CCSID 10i 0 // Specify EBCDIC to ASCII translation table to be used. This is normally // QTCPASC but can be other table depending on the code page you may be // using. In some cases using code page 37 table Q037337850 works better. // The table used must reside in library QUSRSYS. D EATable 10 // Specify the ASCII to EBCDIC translation table to be used. This is // normally QEBCDIC but can be a different table depending on the code page // in use. The table used must reside in library QUSRSYS. D AETable 10 // Specify an IP address to bind the request to a specific Local IP // address. D LocalIP 32 // Specify a port number to bind the request to a specific IP/Port // combination. This value is only valid if a value is specified for // RXS_getUriIn.LocalIP. D LocalPort 10i 0 // Communicating via HTTP requires that certain "headers" be sent first on // the communication line between the client and the server - your IBM i is // the client in this case. When your program calls RXS_getUri, it sends // HTTP headers to the remote web service based on the values specified in // the data structure passed on the RXS_getUri API call. The web remote // server will use those HTTP headers to know how to process the request. // When that server responds to your request it will also send HTTP headers // that detail the communication that took place and give information about // the content passed back from the server (i.e. Content-type: text/xml). // Since you will want to parse the response from the server 99% of the // time we need to make sure the file or data we are parsing only contains // valid XML. HTTP headers are not valid XML, so with this parameter we can // tell the RXS_getUri sub procedure to separate the HTTP headers out into // a separate file with a .hdr extension. Specify RXS_YES to suppress and // separate out the HTTP headers or RXS_NO to keep the HTTP headers in the // response. If RXS_YES is specified and RXS_STMF is the output type, a // file named "xxxxx.hdr" will be created (where "xxxxx" is the filename // specified to contain the output) that will contain the response headers. // Note that the headers will also be present in returned in the fourth // parm of the call to RXS_getUri if it was not omitted. One final note - // specify RXS_YES all the time unless you have requirements that dictate // otherwise. D SprHead 4 // Specifies if the HTTP headers should be sent with the request. // Specifying anything other than RXS_YES, the request must be a POST. // RXS_YES will tell RXS_getUri that all HTTP headers as well as the user // defined headers are se the request. RXS_NO will tell RXS_getUri that no // HTTP headers are sent with the request and only the pReqData parameter // is sent as-is. The value of RXS_USRHDR means that only the user defined // headers are sent with the request. D HTTPHead 7 ``` --- # RXS_getUrlVar() > Extracts a named variable value from a URL query string. Some web services may require their consumers to pull variables off of the URL. This subprocedure will simplify that process. Here is an example URL with variables in **name=value pair** format: `http://mysite.com/rxs/mywebservice?customer=1&code=3` - customer is a variable with a value of 1. - code is a variable with a value of 3. **Note:** Previously, this API failed to return variables where the variable length was a single character. This was fixed in v2.30. ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Parse a URL for a specified name/value pair. Returns the associated // value. D RXS_getUrlVar pr 32767a varying // The name of the variable from which you want to retrieve the value. D pVar 300a value ``` --- # RXS_getXPath() > Returns the current XPath prefix set by RXS_setXPath(). Retrieves the value of the XPath that has been previously set with [RXS_setXPath()](https://isupport.katointegrations.com/rxs/2.x/rxs_setxpath.md). ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Retrieves the value of the XML document's base XPath, as previously set // with RXS_setXPath(). D RXS_getXPath pr like(RXS_XPath) ``` --- # RXS_handOff() > Dynamically calls a subprocedure in an external service program by name, enabling modular web service dispatch. Depending on the chosen application architecture for your RPG Web Services, you may prefer to use separate programs or modules to do the XML parsing, composing and other tasks. With RXS_handOff(), the programmer can dynamically invoke a subprocedure in a service program defined outside of the mainline program. RXS_handOff will take care of activating the specified service program and subprocedure and specify where the program should find the incoming XML file and where it should put the outgoing XML file. The example program called [DOORWAY](https://isupport.katointegrations.com/rxs/2.x/examples/DOORWAY.md) demonstrates how to implement this architecture. This subprocedure works best when offering an RPG Web Service instead of when using a remote web service. The subprocedure & service program containing it must be defined in a data structure like RXS_Subproc. ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Used to hand control over to a non-RXS handler. D RXS_handOff... D pr like(RXS_Error) // Required // Information describing the external service program and subprocedure to // which the process will be handed off. D pHandOff likeds(RXS_SubProc) // Required // The qualified IFS file path of the request XML document. D pInXml value like(RXS_FilePath) // Required // The qualified IFS file path in which the service program should place // the response XML. D pOutXml like(RXS_FilePath) ``` --- # RXS_ignElemNamSpc() > Instructs the parser to ignore a specified XML namespace prefix, simplifying SOAP envelope parsing. Call this subprocedure before [RXS_parse()](https://isupport.katointegrations.com/rxs/2.x/rxs_parse.md) to tell the parser of an XML namespace to ignore while parsing. Ignore simply means it will not add the namespace to the XPath. This is especially useful when parsing SOAP envelopes as the namespace can vary depending on what language created the document. For example, .NET traditionally uses a SOAP envelope like the following: ``. Java on the other hand often generates a SOAP envelope like the following: . Both are entirely valid but cause problems when parsing because in your allHandler subprocedure it is looking for a specific XPath (i.e. `/soapenv:Envelope/soapenv:Body/myelement`). By telling the parser to ignore name spaces for the Envelope and Body SOAP tags the XPath will instead look like the following: /Envelope/Body/myelement. A code sample showing how to make use of RXS_ignElemNamSpc can be found in the RPG-XML Suite installation library in member GETURI2 (i.e. MYRXS/EXAMPLE,GETURI2) Supplying an empty argument for pXPath will ignore all namespaces. (This ability is only available in version 2.0 or later. For versions previous to 2.0, a parameter is required and the prototype does not contain the *NOPASS option.) ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Configure to ignore namespaces when parsing XML. D RXS_ignElemNamSpc... D pr // Specify the XPath to the element where you want name spaces ignored. // When specifying the XPath to an element do NOT include anything at the // end of the string (i.e. '>' or '/' or '/>' which are used to denote // begin element event, content element event, and end element event in // other parts of RPG-XML Suite). Instead just supply the path excluding // the name space you are looking to ignore. // Example: '/Envelope/Body' D pXPath const like(RXS_XPath) options(*nopass) ``` --- # RXS_initTplEng() > Initializes the Template Engine with output type and optional directory overrides before composing XML. Call this subprocedure to initialize the Template Engine environment. Its parameters allow programmers to override default options. To accept a default, pass the keyword '*omit' for a particular parameter. **Note:** Sending to standard out (using RXS_STDOUT for pOutType) when offering a web service generally executes faster because it does not need to go to an IFS stream file first. Using RXS_VAR for pOutType will also execute slightly faster when executing a web service on a remote machine because it does not need to go to an IFS stream file. ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Initializes the template engine, and can be used to temporarily override // default options. D RXS_initTplEng... D pr // Required // Valid values: RXS_STDOUT, RXS_STMF, RXS_VAR // Used to specify where to send output when the internal buffer is // flushed. Passing RXS_STDOUT will route output to standard output (used // when offering a web service from your System i5). Passing RXS_STMF will // route output to an IFS stream file. Passing RXS_VAR will allow the // content to be buffered until RXS_getBuffData() is called to retrieve the // data. D pOutType value like(RXS_Type) // If pOutType = RXS_STMF this parameter specifies the file name of the IFS // file that will receive the output. Specify the full path (i.e. // /myifs/folder/myfile.xml) only when the desired destination is not in // the default transaction directory. If pOutType = RXS_STDOUT, specify // *Omit here. // Valid values: *Omit, file name, qualified file path D pOutFile const options(*omit) D like(RXS_FilePath) // If pOutType = RXS_STMF, this parameter can contain a code page to // override the default. If pOutType = RXS_STMF and this parameter is // omitted, RXS will use the job's default values. If pOutType = // RXS_STDOUT, specify *Omit here. // Valid values: *Omit, code page id D pCodePage 10u 0 const options(*omit) // Specifying the template directory temporarily overrides the location the // Template Engine should look for templates. // Example: /home/myname/templates/. // Valid values: *Omit, qualified directory path D pTplDir like(RXS_FilePath) D const options(*omit) // Specifying the transaction directory temporarily overrides the location // where the Template Engine will place XML transaction files (i.e. XML // documents.) // Example: /home/myname/trans/ // Valid values: *Omit, qualified directory path D pTransDir like(RXS_FilePath) D const options(*omit) // Setting this to *On will enable writing informational messages to the // job log for debugging purposes. Once an application goes into // production, set this value to *Off to keep job logs from filling up. // Valid values: *On, *Off D pDebug n value ``` --- # RXS_libLEExists() > Returns true if a specified library is already in the current job's library list. Used to check the existence of a library entry in the library list before using [RXS_addLibLE()](https://isupport.katointegrations.com/rxs/2.x/rxs_addlible.md) to add one. ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Returns '0' if the library is not in the library list, otherwise returns // its position. D RXS_libLEExists... D pr 3 0 // Required // The name of the target library. D pLib 10a value // Default: *USER D pLibType 10a value options(*nopass) ``` --- # RXS_loadTpl() > Loads a compiled template file into the Template Engine in preparation for variable substitution and output. Use this subprocedure to load a new template into the Template Engine. A template is essentially a file in the IFS that contains XML with named sections and variable data placeholders. Commonly programmers reuse templates across applications or web services. For instance, if many RPG web service applications use the same envelope tag, a separate file can store the header and footer of the envelope (e.g. envelope_header.tpl and envelope_footer.tpl) that encapsulates contents composed using a variety of content templates. **Note:** If your program uses the default section and variable data placeholder delimiters then you can simply use the pFile parameter and not pass the rest (i.e. RXS_loadTpl('myfile.tpl') ). ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Used to load a template file. Can be used to override defaults for // section and variable delimeters. D RXS_loadTpl... D pr // Required // Specify the template file to load into the Template Engine. You can pass // a fully qualified path (e.g. '/www/rxs/template/mytemplate.tpl') or a // relative path based on the default template directory (e.g. // 'mytemplate.tpl'). The default template directory can be found in // physical file RXSCFG. D pFile value like(RXS_FilePath) // Override the default section start delimiter found in RXSCFG with one of // your own. D pSecStart 20a const varying options(*nopass) // Override the default section end delimiter found in RXSCFG with one of // your own. D pSecEnd 20a const varying options(*nopass) // Override the default variable data placeholder start delimiter found in // RXSCFG with one of your own. D pVarStart 20a const varying options(*nopass) // Override the default variable data placeholder end delimiter found in // RXSCFG with one of your own. D pVarEnd 20a const varying options(*nopass) ``` --- # RXS_log() > Sends a message to the job log with a configurable message type (informational, diagnostic, escape, completion, etc.). Use this subprocedure to easily write useful information to the job log. Valid values for the pType parameter are: - RXS_ESCAPE - RXS_COMP - RXS_DIAG - RXS_INFO - RXS_INQ - RXS_NOTIFY - RXS_RQS - RXS_STATUS ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Write a message to the job log. D RXS_log pr // The message type. // Valid values: RXS_ESCAPE, RXS_COMP, RXS_DIAG, RXS_INFO, RXS_INQ, // RXS_NOTIFY, RXS_RQS, RXS_STATUS D pType const like(RXS_MsgType) // The text of the message that should appear in the job log. D pMsg 32767a const options(*varsize) ``` --- # RXS_moveFile() > Moves an IFS file to a different directory, optionally renaming it. This subprocedure allows the programmer to move an existing IFS file to a different folder in the IFS. Additionally, it allows for the file to be renamed in the new location. This subprocedure can also be used to rename an existing IFS file by specifying the same filepath in the pFrom and pTo parameters but with a different filename (or extension). ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Moves the specified IFS file to a different specified location. D RXS_moveFile pr 10i 0 // The qualified IFS file name of the file to be moved. // Example: /myFolder/myFile.xml D pFrom value like(RXS_FilePath) // The qualified IFS file path to which the file will be moved. // Example: /myNewFolder/myNewFileName.xml D pTo value like(RXS_FilePath) ``` --- # RXS_nextUnqChar() > Returns the next sequential unique 15-character value from a data queue for generating unique file names. Works the same as RXS_nextUnqNbr except it returns a 15 byte character. It helps when creating IFS files that need to be unique by eliminating the need for the %Char Built-In Function in concatenation of variables. ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Returns the next available number from the data area RXS/RXSUNQ as a // character string. D RXS_nextUnqChar... D pr 15a ``` --- # RXS_nextUnqNbr() > Returns the next sequential unique number from the RXS/RXSUNQ data area for generating unique file names. Use this subprocedure to easily obtain the next sequential number from data area RXS/RXSUNQ. Useful when creating IFS files that need to be unique. ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Returns the next available number from the data area RXS/RXSUNQ. D RXS_nextUnqNbr pr 15 0 ``` --- # RXS_out() > Writes a character string directly to standard output, bypassing the Template Engine. This is a "raw output" subprocedure that will allow you to push data to standard out in any fashion that suits your needs. An example usage is within [RXS_stdOutError()](https://isupport.katointegrations.com/rxs/2.x/rxs_stdouterror.md) which simply composes a small XML stream to send to standard out without using the Template Engine. ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Writes data to standard out. D RXS_out pr // The data to be sent to standard out. D pData 65535a Value varying ``` --- # RXS_outFromFile() > Streams the entire contents of an IFS file to standard output. This sends the entire contents of a file in the IFS to standard out. This is useful when using the Template Engine to compose files in the IFS. Once the XML file is created, use RXS_outFromFile() to write the entire contents to standard out. Use this when writing RPG Web Services residing on your IBM i that other programs call and NOT when consuming web services on a remote system. **Note:** QTMHHTP1 will require at least *RW permissions on the file you are attempting to read and output. ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Writes contents of IFS file to standard out. D RXS_outFromFile... D pr // The qualified file name in the IFS. // Example: /myFolder/myFile.xml D pFile value like(RXS_FilePath) ``` --- # RXS_parse() > Parses XML from an IFS file or RPG variable, dispatching events to handlers registered via RXS_addHandler() and related subprocedures. Call this subprocedure to parse either an XML document residing in the IFS or the contents of an RPG variable that contains XML. Note: Sending to standard out (using RXS_STDOUT for pOutType) when offering a web service generally executes faster because it does not need to go to an IFS stream file first. Using RXS_VAR for pOutType will also execute slightly faster when executing a web service on a remote machine because it does not need to go to an IFS stream file. Ordinarily you will set up or "register" handler pointers using one or all of the following subprocedures before calling RXS_parse(): - [RXS_addHandler()](https://isupport.katointegrations.com/rxs/2.x/rxs_addhandler.md) - [RXS_allElemBeginHandler()](https://isupport.katointegrations.com/rxs/2.x/rxs_allelembeginhandler.md) - [RXS_allElemContentHandler()](https://isupport.katointegrations.com/rxs/2.x/rxs_allelemcontenthandler.md) - [RXS_allElemEndHandler()](https://isupport.katointegrations.com/rxs/2.x/rxs_allelemendhandler.md) - [RXS_allAttrHandler()](https://isupport.katointegrations.com/rxs/2.x/rxs_allattrhandler.md) The RXS_parse() function will run even if you do not register any handlers. However, if you do not specify any handlers, the parser will only notify the program when it finds XML errors. It will not return notice of any other events. Every locally defined subprocedure registered with the parser as an event handler must have the four parameters listed in the following example: ```rpgle D Handler 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) ``` ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Used to parse XML. Returns a 4-byte integer. The return value will be 0 // unless RXS_parseQuit() is invoked during parsing and a non-zero value is // passed to the subprocedure. D RXS_parse pr 10i 0 // Used to specify a file in the IFS or actual XML residing in an RPG // variable. If an IFS file is specified it must either be fully qualified // (i.e. /home/user/mydoc.xml) or must reside in the default transaction // directory (i.e. /www/rxs/trans.) If it resides in the default // transaction directory then you can just specify it as 'mydoc.xml.' D pFilePathOrData... D value like(RXS_XmlData) // Use RXS_STMF if the value passed in pFilePathOrData is a path to an IFS // file. Use RXS_VAR if the value passed in pFilePathOrData contains XML. // Valid values: RXS_STMF, RXS_VAR D pType value like(RXS_Type) // This parameter tells the XML parser which procedure in your program to // call if the parser encounters an error. It is of type PROCPTR and can be // obtained by using the %PADDR Built-In Function (e.g. // %PADDR(myErrHandler)). You can name the local subprocedure for capturing // errors anything you want, but it must specify these parameters in this // order with the data types as specified in the sample error handler data // structure. D pErrProcPtr * procptr value // Override the default element begin value of '>' with the value of your // choice. Recommend to leave at default unless you are experiencing // codepage issues. D pElemBegVal 10a value options(*nopass) // Override the default element content value of '/' with the value of your // choice. Recommend to leave at default unless you are experiencing // codepage issues. D pElemContentVal... D 10a value options(*nopass) // Override the default element begin value of '/>' with the value of your // choice. Recommend to leave at default unless you are experiencing // codepage issues. D pElemEndVal 10a value options(*nopass) // Override the default attribute begin value of '@' with the value of your // choice. Recommend to leave at default unless you are experiencing // codepage issues. D pAttrVal 10a value options(*nopass) ``` --- # RXS_parseQuit() > Aborts an in-progress XML parse from within a handler subprocedure. Call this subprocedure from a user-defined handler procedure to immediately quit parsing the current XML data and return to the procedure which called [RXS_parse()](https://isupport.katointegrations.com/rxs/2.x/rxs_parse.md). This can be useful if you are parsing a very large XML document and the only data you wish to extract is near the beginning of the document. ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Abort XML processing from within the parsing subprocedure. D RXS_parseQuit pr // A custom value to be returned from RXS_parse(). D rtncde 10i 0 const options(*nopass) ``` --- # RXS_putEnvVar() > Sets or creates a job-level environment variable in key=value format. This API allows the programmer to set or create a job-level environment variable. The environment variable and data being set for it are both case sensitive, and must be specified in **key=value** format, like so: `IS_RPG_AWESOME=YES` ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Set or modify a job-level environment variable. D RXS_putEnvVar pr // The name of the environment variable to set, in key=value format. // Example: IS_RPG_AWESOME=YES D pEnvVar 32767a value varying ``` --- # RXS_readStdIn() > Reads an HTTP POST body (e.g., inbound XML) from stdin into an RPG variable. This subprocedure will allow you to read the XML data that was sent to you via an HTTP POST. Once the XML is obtained it can be passed to the parser using [RXS_parse()](https://isupport.katointegrations.com/rxs/2.x/rxs_parse.md). ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Read data from standard in. The contents of the HTTP POST will be // returned to the calling program in the return parameter. D RXS_readStdIn... D pr like(RXS_XmlData) ``` --- # RXS_readToFile() > Reads an HTTP POST body from stdin and writes it to an IFS file (supports up to 16 MB). This subprocedure allows the programmer to read the XML data into a file that was sent to your program via an HTTP POST. Once the XML is obtained it can be passed to the parser using [RXS_parse()](https://isupport.katointegrations.com/rxs/2.x/rxs_parse.md). This subprocedure allows the programmer to read up to 16MB of XML. If an application needs to transmit more than 16MB, other methods may better serve the requirement. XML is probably not the best method for data replication, or for transferring thousands of records at a time and similar procedures. The extra overhead incurred by passing tags causes problems. For example, the following XML takes 36 characters to transmit 3 characters of data: `123` ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Read standard in to IFS file. D RXS_readToFile... D pr // The qualified name of the IFS file into which to read the results. // Example: /myFolder/web_service_request.xml D pFile value like(RXS_FilePath) ``` --- # RXS_rmvLibLE() > Removes a library from the current job's library list. Used to remove a library entry from the library list. This is usually used at the end of a program in conjunction with [RXS_addLibLE()](https://isupport.katointegrations.com/rxs/2.x/RXS_addLibLE.md) to remove a library that was added at the beginning of the program. If the pLib parameter is not passed, the first library in the library list will be removed. ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Removes specified library from the library list. D RXS_rmvLibLE pr // The name of the library list entry to be removed from the library list. D pLib 10a value options(*nopass) ``` --- # RXS_setParseEnc() > Sets the character encoding (e.g., UTF-8, ISO-8859-1) used when parsing XML content. Call this subprocedure before [RXS_parse()](https://isupport.katointegrations.com/rxs/2.x/rxs_parse.md) to tell the parser what encoding to use while parsing the character data in elements and attributes. By default the parser will look at the first few characters of the file to attempt to determine what encoding should be used. By default, and more often than not, UTF-8 is used. That can cause problems if the data was actually obtained using CCSID 819 (i.e. encoding ISO88591). If you are having trouble parsing characters like Ü then your data is probably being returned as ISO88591 vs. UTF-8 (as many XML declarations incorrectly state). **Note:** An excellent reference for code pages can be found [here](http://www.tachyonsoft.com/cpindex.htm). ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Configure encoding used to parse XML. D RXS_setParseEnc... D pr // Specify the parse encoding that the parser should use. All of these // constants can be found in copy book RXSCP. // Valid values: RXS_UTF8, RXS_UTF16, RXS_ISO88591, RXS_USASCII D pPrsEnc 25a const ``` --- # RXS_setTplDir() > Overrides the template directory for the current job. Use this subprocedure when your application needs to temporarily change the template directory. The temporary value can be reset within a job by calling [RXS_initTplEng()](https://isupport.katointegrations.com/rxs/2.x/RXS_initTplEng.md). Note that this function does not change the RXSCFG physical file. Instead it stores the override value within the job. ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Changes the IFS path of the currently configured template directory. D RXS_setTplDir... D pr // Required // Specify the temporary directory to use for templates. // Example: /home/myname/template/ D pDir value like(RXS_FilePath) ``` --- # RXS_setTransDir() > Overrides the transaction directory for the current job. Use this subprocedure to temporarily change the transaction directory. The temporary value can be reset within a job by calling [RXS_initTplEng()](https://isupport.katointegrations.com/rxs/2.x/RXS_initTplEng.md). Note that this function does not change the RXSCFG physical file. Instead, it stores the override value within the job. ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Changes the IFS path of the currently configured transaction directory. D RXS_setTransDir... D pr // Required // Specify the temporary directory to use for transactions. // Example: /home/myname/template/ D pDir value like(RXS_FilePath) ``` --- # RXS_setXPath() > Sets a base XPath prefix for DOM lookups, reducing repetition when accessing deeply nested elements. **NOTE:** The RXS_DOM* APIs were created to allow for a different approach to parsing XML documents. Depending on the complexity of your XML and what data elements you are parsing, the RXS_DOM* APIs can make the syntax for parsing simpler. The simpler syntax comes with a cost because the entire XML document is parsed and stored in memory so you can access any element data at any time (think of it as being able to "CHAIN" to the XML structure - random access). Performance for smaller XML files is comparable for the two XML parsers within RPG-XML Suite, but the larger the XML file the bigger the divide. For example, a large 4MB XML file will take 200 seconds with the event based parser and 600 seconds with the DOM parser. So make sure to factor that into your decision on whether to use the RXS_DOM* APIs to parse or the event based parser. Use this subprocedure to set the base value of the XML document's XPath. This is typically used for an XML structure that contains long element names and/or many parent-child relationships. This XPath is used in conjunction with the [RXS_DOMGetData()](https://isupport.katointegrations.com/rxs/2.x/RXS_DOMGetData.md) and [RXS_getXPath()](https://isupport.katointegrations.com/rxs/2.x/RXS_getXPath.md) APIs. ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Used to set the base value of the XML document's XPath. D RXS_setXPath pr // An XPath segment value. D pXPath const like(RXS_XPath) ``` --- # RXS_soapDecode() > Encodes or decodes XML entities (e.g., <, >) for use in RPC-style SOAP payloads. Call this subprocedure to take XML from its encoded form (i.e. `<tagname>content</tagname>`) to actual XML that can be parsed (i.e. `content`). The reason this subprocedure is named soapDecode speaks to why this API is needed in the first place. Many programmers in .NET and Java environments have their code generated which inherently means the encoding style usually defaults to RPC (Remote Procedure Call) vs. Document Literal. Note that RXS_soapDecode can also be used to encode values if your program is composing the XML to be sent to an RPC style web service. In the end RXS_soapDecode is simply an easy to use find/replace mechanism to use on files and variable data. The following are the default from/to array values if pFrom and pTo are not specifed on the call to RXS_soapDecode: ```rpgle from(1) = '<'; to(1) = '<'; from(2) = '>'; to(2) = '>'; from(3) = '"'; to(3) = '"'; from(4) = '''; to(4) = ''''; from(5) = '&'; to(5) = '&'; ``` ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Converts XML from encoded to decoded form. D RXS_soapDecode pr // Used to specify a file in the IFS or actual XML residing in an RPG // variable. If an IFS file is specified it must either be fully qualified // (i.e. /home/user/mydoc.xml) or must reside in the default transaction // directory (i.e. /www/myrxs/trans.) If it resides in the default // transaction directory then you can just specify it as 'mydoc.xml.' D pFileOrData like(RXS_XmlData) // Use RXS_STMF if the value passed in pFilePathOrData is a path to an IFS // file. Use RXS_VAR if the value passed in pFilePathOrData contains XML. // Valid values: RXS_STMF, RXS_VAR D pType value like(RXS_Type) // Used to specify a list of from values in an array that correspond to the // to values in pTo. // Default: from(1)='&lt;', from(2)='&gt;', from(3)='&quot;', // from(4)='&apos;', from(5)=&amp;' D pFrom 10a dim(10) varying options(*nopass) // Used to specify a list of to values in an array that correspond to the // from values in pFrom. // Default: to(1)='', to(3)='"', to(4)='\'', to(5)='&' D pTo 10a dim(10) varying options(*nopass) ``` --- # RXS_stdOutError() > Outputs a structured XML error message to standard output for web service error responses. Use this subprocedure to output (to standard out) an xml error message detailing an error that has taken place. This is usually used with either [RXS_catchError()](https://isupport.katointegrations.com/rxs/2.x/RXS_catchError.md) to display errors from the call stack or in conjunction with the errHandler subprocedure. ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Writes an error data structure to standard out. D RXS_stdOutError... D pr // Required // Root element name of the XML document to be generated. D pXmlTag 256a value varying // Required // Error information to be displayed. D pErr value likeds(RXS_Error) // Required // Indicates if an HTTP header should be generated. D pWrtHdr n value ``` --- # RXS_throwError() > Throws a programmer-defined error message for use with RPG MONITOR/ON-ERROR blocks. RXS_throwError() and [RXS_catchError()](https://isupport.katointegrations.com/rxs/2.x/RXS_catchError.md) are used as an extension to the RPG compiler's MONITOR op-code. When IBM added the MONITOR op-code they only allowed for compiler predefined error messages to be "caught" on the corresponding ON-ERROR statement. That means you can't have an ON-ERROR statement watching for a programmer defined error code. With just a little bit of additional code we can utilize the MONITOR and ON-ERROR clauses to our benefit. By surrounding a piece of code that could be erroneous with the MONITOR op-code we can use the ON-ERROR clause to catch any errors that are thrown by programs further down the program call stack, and then using [RXS_catchError()](https://isupport.katointegrations.com/rxs/2.x/RXS_catchError.md) to retrieve the most recent error off of the program call stack. For example, if PGMA wraps a MONITOR around a call to PGMB and PGMB uses RXS_throwError() to generate an error, then the next line of code executed will be the ON-ERROR clause in PGMA because the RPG runtime recognizes that an error occurred and it looks for it's next stopping point (ON-ERROR is one such stopping point). RXS_catchError can then be used within the ON-ERROR clause to retrieve the last error off of the program call stack. At that point PGMA has access to the error code, severity, program name and error text. The decision of how to continue is up to PGMA as it caught the error and avoided an abnormal end. This is similar to using a *PSSR subroutine except that with *PSSR your program doesn't regain control after the *PSSR sub routine executes. See the program ERR1 for more details on how to use this API. ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Throws an error and returns an error data structure. Can be used to // define custom errors and messages. D RXS_throwError pr extproc('ERROR_THROW') // Required // A code to uniquely identify this error. // Example: RXP0000001 D pCode value Like(RXS_Error.code) // Required // The severity of the error. // Example: 100 D pSeverity value Like(RXS_Error.severity) // Required // The program that is creating or throwing the error. D pPgm value Like(RXS_Error.pgm) // Required // The error text to be sent with the error. D pText value Like(RXS_Error.text) ``` --- # RXS_timestampToChar() > Converts an IBM i timestamp to an XML-formatted string using a customizable date/time pattern. Use RXS_timestampToChar() to easily convert a timestamp coming from your database or program to an XML format that matches the requirements in the XSD (XML Schema Definition). This will save the headache of programming for all of the different timestamp formats out there and doing a bunch of sub-stringing and concatenation. Valid keywords for pFormat are listed below: - yyyy = Year - MM = Month - dd = Day - hh = Hour - mm = Minute - ss = Second - SS = Millisecond Typical usage would look like: `myStr = RXS_timestampToChar('yyyy-MM-ddThh.mm.ss': %Timestamp());` ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Converts a timestamp field into a character value. D RXS_timestampToChar... D pr 50a varying // Required // The timestamp format in which to return the character data. D pFormat 30a value // Required // The timestamp to be converted. D pTimestamp z value ``` --- # RXS_updVar() > Updates the value of a named variable placeholder in the currently loaded template. Use this subprocedure to update the contents of a template engine variable defined in a section (e.g. `.:phone:.`) ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Replaces a specified template variable with a provided value. D RXS_updVar pr // The name of the variable to replace with the value specified in the // second parameter. // Example: phone (for the template variable .:phone:.) D pName 30a const varying // The value to replace the template variable's place holder. // Example: 123-456-7890 (to populate the example template variable // .:phone:., above) D pValue 65535a const varying // Specify *On for this parameter in order to trim the data of blanks at // the beginning and end of the string or *Off to maintain the spaces as // passed. // Default: *On D pTrim n value options(*nopass) ``` --- # RXS_writeXMLHdr() > Outputs an HTTP Content-type: text/xml header for web service responses. Use this subprocedure to quickly write out the barebones http headers for a web service. It is basically outputting Content-type: text/xml followed by two carriage return line feeds. Note that this subprocedure could be used to write out the http headers instead of putting them in a template for the Template Engine to send them. Use this when writing RPG Web Services residing on your iSeries that other programs call and NOT when consuming web services on a remote system. ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Writes HTTP headers to standard out. D RXS_writeXMLHdr... D pr ``` --- # RXS_wrtSection() > Writes a template section to the output buffer after variable substitution, optionally flushing buffered data. Call this subprocedure to write out a section (e.g. ::envelope_begin.) The most common use will be to call RXS_wrtSection after one or many calls have been made to [RXS_updVar()](https://isupport.katointegrations.com/rxs/2.x/RXS_updVar.md). Make sure to specify the flush parameter before your program ends to ensure all data has been processed in the buffer and sent to either standard out or an IFS stream file. ## Subprocedure Prototype ### IBM i V5R4+ ```rpgle // Writes a template section to the buffer. D RXS_wrtSection... D pr // Specify one or many sections to write. When specifying more than one // section, separate them with a space. // Example: section1 (will write template variable ::section1) D pSections 1024a value varying // Flush everything that has been written to either standard out or an IFS // File. The destination will depend on what was specified on the pOutType // parameter for subprocedure RXS_initTplEng(). Note that if RXS_VAR was // specified for pOutType on RXS_initTplEng(), the flush will have no // effect here. Instead when RXS_getBuffData() is called *On should be // specified to flush the buffer. D pFlush n options(*nopass) value ``` --- # Apply License (APYLIC) > Applies a permanent or temporary activation key for RPG-XML Suite 2.x. 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-2.x/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/2.x/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-2.x/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/2.x/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-2.x/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-XML Suite. 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-2.x/dspver.png "Display Version (DSPVER)") If you don't receive that message or receive an error message, please contact us at isupport@katointegrations.com. --- # Create RXS Server (CRTRXSSVR) > Creates an Apache HTTP server instance configured for use with RPG-XML Suite 2.x. The Create RXS HTTP Server (CRTRXSSVR) command allows the user to create an HTTP server instanace 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: ```rpgle 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/2.x/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/2.x/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/2.x/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. `port-number` : 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 RXSRTRCTL 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-2.x/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-2.x/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/2.x/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. INZRXSRTR (Initialize RXS Router) 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 Template Engine. The BLDTPL command aids in composing RPG-XML Suite template (*.tpl) files, which are used with the Template/Composition Engine subprocedures ([RXS_InitTplEng()](https://isupport.katointegrations.com/rxs/2.x/rxs_inittpleng.md), [RXS_WrtSection](https://isupport.katointegrations.com/rxs/2.x/rxs_wrtsection.md), [RXS_UpdVar()](https://isupport.katointegrations.com/rxs/2.x/rxs_updvar.md), and [RXS_GetBuffData()](https://isupport.katointegrations.com/rxs/2.x/rxs_getbuffdata.md)) to compose XML documents. **Please follow our example [Creating an RXS Template](https://isupport.katointegrations.com/rxs/2.x/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. --- # Build XML Parsing Subprocedure (BLDPRS) > Generates an RPG handler subprocedure for XML event-based parsing from a sample XML document. 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/2.x/rxs_parse.md) subprocedure. 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/2.x/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, 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. To start with creating a template file, we need to create a file in the IFS. This command uses QSHELL to create an IFS stream file using CCSID 819. Note that this command is **case-sensitive**. `QSH CMD('touch -C 819 /www/myrxs/templates/bldtpl001.xml')` 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. Note that to make your life easier, you want this to be as complete an example 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/bldtpl001.xml'` Now, paste your sample XML into the resulting editor window. For the sake of this example, we'll use the following XML: ```xml Sample Resident 999 Totally A Real Street Cityville OH 12345 123-456-7890 987-654-3210 ``` While in the Edit File editor select F2 to save the document changes. Now it is time to invoke the BLDTPL command to generate a *.tpl file that will facilitate composing the PostAdr XML document. `BLDTPL IFSXMLLOC('/www/myrxs/templates/bldtpl001.xml') IFSTPLLOC('/www/myrxs/templates/bldtpl001.tpl') INDENT(2)` The IFSXMLLOC parameter is the location of the XML file that was created in the above steps. The IFSTPLLOC is where we want the new bldtpl001.tpl file to be located – place it in the location of all other RPG-XML Suite templates. The last parameter, INDENT, allows you to specify how the template's XML should be indented. Note that indenting is purely for ease of editing. See below for the resulting template file located at /www/myrxs/templates/bldtpl001.tpl - use EDTF to open it. Note that all elements and attributes have had their values replaced with variable place holders (i.e. .:variable:.) respective to the element or attribute's name. ```xml .:first:. .:last:. .:street:. .:cty:. .: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. This is because of the other main concept used in RXS template files - sections. A section is a portion of a template file that is referred to by name. Sections can be written out multiple times in an XML document. Sections are also not created by BLDTPL - you will need to go in and 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 an example of how to split up our example XML into sections: ```xml ::PostAdr_beg .:first:. .:last:. .:street:. .:cty:. .: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 - our document could have one phone number, or a thousand phone numbers - or even none! 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. --- # 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() 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 ``` --- # 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/2.x/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/2.x/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/2.x/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. --- # Calling the OAGIS SalesOrder Web Service > Proof-of-concept RPG-XML Suite 2.x example processing OAGIS SalesOrder XML documents, including source code, template file, and sample XML. This proof of concept was developed to demonstrate RPG-XML Suite's ability to process and respond with OAGIS specified documents. In this program, we work exclusively with SalesOrder documents, and work with ProcessSalesOrder and RespondSalesOrder. Due to the verbose nature of the OAGIS specification, this proof of concept has the following limits: - Accepts a maximum of 5 SalesOrderLine elements. - Implements a very limited subset of the specifications - Has hardcoded data and does not use DB2 tables. ## Source Code ```rpgle //?*************************************************************************************** //?@Author: Adam Taylor //?@Desc: Read incoming ProcessSalesOrder XML via STDIN, create a RespondSalesOrder //? in an XML file, and return it to the requestor via STDOUT. //?@Notes: This example only accounts for up to 5 items being present in a // ProcessSalesOrder, and is a limited subset of both XML documents as compared // to their full form per OAGIs. //?*************************************************************************************** H dftactgrp(*no) bnddir('RXSBND') /copy rxs,RXSCp ?RXS_* procedures & definitions D gError ds likeds(RXS_Error) inz D salesOrder ds qualified inz D sndLogicalId 10a D sndCmpntId 12a D sndRefId 5a D sndConfirmURI 40a Varying D sndConfirmCd 15a D sndAuthId 12a D rcvLogicalId 10a D rcvId 10a D crtDateTime d D BODID 3a Varying D saleOrderType 1a D saleHdrDesc 50a Varying D noteAuthor 4a Varying D noteDateTime d D noteStatus 1a D note 50a Varying D totAmtCurType 6a D totAmt 8 2 D salesOrderLine ds qualified inz dim(5) D lineNumber 5 0 D description 50a Varying D originCountry 50a Varying D serialNumber 20a D gLineCnt s 10i 0 Inz(0) D counter s 10i 0 Inz(0) D gReqFile s like(RXS_FilePath) D gRspFile S like(RXS_FilePath) 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) D errHandler pr D pCurLine 10i 0 value D pCurCol 10i 0 value D pErrStr 1024a value varying /free monitor; gReqFile = RXS_cmpTransFile('_': '.xml': 'cargill_req'); gRspFile = RXS_cmpTransFile('_': '.xml': 'cargill_rsp'); RXS_readToFile(gReqFile); exsr parse; exsr compose; exsr respond; on-error; RXS_stdOutError('error': RXS_catchError(): *on); endmon; *inlr = *On; //?-------------------------------------------------------------------------------------- //?@Author: Adam Taylor //?@Desc: Prime parsing engine //?-------------------------------------------------------------------------------------- begsr parse; monitor; // Ignore all namespaces. RXS_ignElemNamSpc(); RXS_allElemContentHandler(%paddr(allHandler)); RXS_allAttrHandler(%paddr(allHandler)); RXS_parse(gReqFile : RXS_STMF : %paddr(errHandler)); on-error; gError = RXS_catchError(); endmon; endsr; //?-------------------------------------------------------------------------------------- //?@Author: Adam Taylor //?@Desc: Build RespondSalesOrder XML file using Template Engine //?-------------------------------------------------------------------------------------- begsr compose; monitor; // Composing our XML RespondSalesOrder and storing it in a STMF RXS_initTplEng(RXS_STMF: gRspFile: *omit: *omit: *omit: *off); RXS_loadTpl('RespondSalesOrder.tpl'); RXS_updVar('LogicalID' : salesOrder.sndLogicalId); RXS_updVar('ComponentID' : salesOrder.sndCmpntId); RXS_updVar('ReferenceID' : salesOrder.sndRefId); RXS_updVar('languageID' : 'en-US'); RXS_updVar('ConfirmationCode' : salesOrder.sndConfirmCd); RXS_updVar('AuthorizationID' : salesOrder.sndAuthId); RXS_updVar('BODID' : salesOrder.BODID); RXS_updVar('CreationDateTime' : %Char(salesOrder.crtDateTime)); RXS_updVar('currencyID' : salesOrder.totAmtCurType); RXS_updVar('TotalAmount' : %Char(salesOrder.totAmt)); RXS_updVar('SaleHeaderDescription' : salesOrder.saleHdrDesc); RXS_updVar('author' : salesOrder.noteAuthor); RXS_updVar('entryDateTime' : %Char(salesOrder.noteDateTime)); RXS_updVar('status' : salesOrder.noteStatus); RXS_updVar('Note' : salesOrder.note); RXS_updVar('Code' : 'INI'); RXS_updVar('EffectiveDateTime' : %Char(%Date())); RXS_updVar('ChangeDateTime' : %Char(%Date() - %Days(3))); RXS_updVar('FromStateCode' : 'ORD'); RXS_updVar('ReasonCode' : 'CDE'); RXS_updVar('ToStateCode' : 'PRC'); RXS_updVar('actionCode' : 'Always'); RXS_updVar('ResponseExpression' : 'Successful'); RXS_wrtSection('RespondSalesOrder_beg'); // Print out however many order lines we parsed. for counter = 1 To 5; if salesOrderLine(counter).lineNumber > 0; RXS_updVar('LineNumber' : %Char(salesOrderLine(counter).lineNumber)); RXS_updVar('CountryOfOriginCode' : salesOrderLine(counter).originCountry); RXS_updVar('Description' : salesOrderLine(counter).description); RXS_updVar('SerialNumber' : salesOrderLine(counter).serialNumber); RXS_wrtSection('SalesOrderLine'); endif; endfor; // Finalize XML file, flush buffer to XML file RXS_wrtSection('RespondSalesOrder_end' : *On); on-error; gError = RXS_catchError(); endmon; endsr; //?-------------------------------------------------------------------------------------- //?@Author: Adam Taylor //?@Desc: Return RespondSalesOrder via STDOUT //?-------------------------------------------------------------------------------------- begsr respond; monitor; RXS_writeXmlHdr(); RXS_outFromFile(gRspFile); on-error; gError = RXS_catchError(); endmon; endsr; /end-free //--------------------------------------------------------------------------------------- // @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 // For the sake of this example, we're loading the repeating // SalesOrderLine elements into an array, limited at 5 elements. // In normal use, you would most likely want to load these into a // DB2 table. baseEnv = '/Envelope/Body/ProcessSalesOrder'; select; when pXPath = baseEnv +'/ApplicationArea/Sender/LogicalID/'; salesOrder.sndLogicalId = pData; when pXPath = baseEnv +'/ApplicationArea/Sender/ComponentID/'; salesOrder.sndCmpntId = pData; when pXPath = baseEnv +'/ApplicationArea/Sender/ReferenceID/'; salesOrder.sndRefId = pData; when pXPath = baseEnv +'/ApplicationArea/Sender/ConfirmationCode'+ '@listURI'; salesOrder.sndConfirmURI = pData; when pXPath = baseEnv +'/ApplicationArea/Sender/ConfirmationCode/'; salesOrder.sndConfirmCd = pData; when pXPath = baseEnv +'/ApplicationArea/Sender/AuthorizationID/'; salesOrder.sndAuthId = pData; when pXPath = baseEnv +'/ApplicationArea/Receiver/LogicalID/'; salesOrder.rcvLogicalId = pData; when pXPath = baseEnv +'/ApplicationArea/Receiver/ID/'; salesOrder.rcvId = pData; when pXPath = baseEnv +'/ApplicationArea/CreationDateTime/'; salesOrder.crtDateTime = %DATE(pData : *ISO); when pXPath = baseEnv +'/ApplicationArea/BODID/'; salesOrder.BODID = pData; when pXPath = baseEnv +'/DataArea/SalesOrder/SalesOrderHeader'+ '/Description/'; salesOrder.saleHdrDesc = pData; when pXPath = baseEnv +'/DataArea/SalesOrder/SalesOrderHeader/Note'+ '@author'; salesOrder.noteAuthor = pData; when pXPath = baseEnv +'/DataArea/SalesOrder/SalesOrderHeader/Note'+ '@entryDateTime'; salesOrder.noteDateTime = %DATE(pData : *ISO); when pXPath = baseEnv +'/DataArea/SalesOrder/SalesOrderHeader/Note/'; salesOrder.note = pData; when pXPath = baseEnv +'/DataArea/SalesOrder/SalesOrderHeader'+ '/TotalAmount@currencyID'; salesOrder.totAmtCurType = pData; when pXPath = baseEnv +'/DataArea/SalesOrder/SalesOrderHeader'+ '/TotalAmount/'; salesOrder.totAmt = %DEC(pData : 8 : 2); // Process up to 5 incoming line items. when pXPath = baseEnv +'/DataArea/SalesOrder/SalesOrderLine/LineNumber/'; gLineCnt += 1; salesOrderLine(gLineCnt).lineNumber = %Dec(pData : 5 : 0); when pXPath = baseEnv +'/DataArea/SalesOrder/SalesOrderLine/Item'+ '/Description/'; salesOrderLine(gLineCnt).description = pData; when pXPath = baseEnv +'/DataArea/SalesOrder/SalesOrderLine/Item'+ '/CountryOfOriginCode/'; salesOrderLine(gLineCnt).originCountry = pData; when pXPath = baseEnv +'/DataArea/SalesOrder/SalesOrderLine/Item'+ '/SerialNumber/'; salesOrderLine(gLineCnt).serialNumber = pData; endsl; /end-free P e P errHandler B D errHandler PI D pCurLine 10i 0 value D pCurCol 10i 0 value D pErrStr 1024a value varying /free gError.code = 'SALE001'; gError.severity = 100; gError.pgm = 'SALE001.errHandler'; gError.text = 'Line:' + %char(pCurLine) + ' Col:' + %char(pCurCol) + ' ' + pErrStr; /end-free P E ``` ## Template File ```xml .:LogicalID:. .:ComponentID:. .:ReferenceID:. .:ConfirmationCode:. .:AuthorizationID:. .:CreationDateTime:. .:BODID:. .:LogicalID:. .:ComponentID:. .:ReferenceID:. .:ConfirmationCode:. .:AuthorizationID:. .:CreationDateTime:. .:BODID:. .:ResponseExpression:. .:Code:. .:EffectiveDateTime:. .:ReasonCode:. .:FromStateCode:. .:ToStateCode:. .:ChangeDateTime:. .:SaleHeaderDescription:. .:Note:. .:TotalAmount:. ::SalesOrderLine .:LineNumber:. .:Description:. .:CountryOfOriginCode:. .:SerialNumber:. ::RespondSalesOrder_end ``` ## Sample XML Request ```xml 1159963824 64720-22-358 16683 Always 489665871337 4283699511 1594826735 2010-07-13 485 Example order description would go here. Some notes would go here. 12300.99 100 Item description here. Canada 153-8894-778-9636-45 200 2nd Item description here. Spain 956-4421-263-5684-23 300 3rd Item description here. Belgium 223-8695-748-9644-78 400 A Fourth Item description here. Peru 845-9595-748-3625-24 ``` --- # Call SOAP Web Service > RPG-XML Suite 2.x example composing a SOAP XML request with the Template Engine, sending it via RXS_getUri(), and parsing the XML response. Compose a SOAP XML document to send to a web service hosted on http://www.w3schools.com. Use [RXS_getUri()](https://isupport.katointegrations.com/rxs/2.x/rxs_geturi.md) to send the document to the web service making sure to specify all of the appropriate headers. And lastly, receive the response back from the web service and parse the document to obtain the end result data. The web service is simple in concept in that it is passing in a Fahrenheit temperature and converting it to Celsius and returning that value to this program. This program also shows how to make use of [RXS_ignElemNamSpc()](https://isupport.katointegrations.com/rxs/2.x/rxs_ignelemnamspc.md) which is very useful when parsing SOAP XML documents. ## Source Code ```rpgle //******************************************************************************************* //@Author: Kato Integrations //@Descr: Compose a SOAP xml document to send to a web serivce hosted on www.w3schools.com. // Use RXS_getUri to send the document to the web service making sure to specify // all of the appropriate headers. And lastly, receive the response back from the // web service and parse the document to obtain the end result data. // The web service is simple in concept in that it is passing in a Fahrenheit // temperature and converting it to Celsius and returning that value to this program. // This program also shows how to make use of the RXS_ignElemNamSpc API which is // very useful when parsing SOAP XML documents. //@Notes: //******************************************************************************************* H dftactgrp(*no) bnddir('RXSBND') /copy rxs,RXSCp RXS_* procedures & definitions // //Local Prototypes // 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) D errHandler pr D pCurLine 10i 0 value D pCurCol 10i 0 value D pErrStr 1024a value varying // //Global Variables // D gError ds likeds(RXS_Error) inz D gCelciusValue s 10i 0 //Used for RXS_getUri API D gInCfg ds likeds(RXS_GetUriIn) inz D gRspData s like(RXS_XmlData) D gRspHttpHdr s like(RXS_XmlData) D gReqData s like(RXS_XmlData) /free clear gError; exsr compose; if gError.code <> *blanks; return; endif; exsr transmit; if gError.code <> *blanks; return; endif; exsr parse; RXS_log(RXS_DIAG: 'Result:' + %char(gCelciusValue)); *inlr = *on; //------------------------------------------------------------------------------------------- //@Author: Kato Integrations //@Desc: Compose the xml necessary to send to the www.w3schools.com web service. Template // geturi2.tpl can be found in /www/myrxs/templates/geturi2.tpl. // // RXS_initTplEng is initializing the template engine and allows you to specify where // the composed document is located. In this case we want to eventually obtain the // created XML and place it into an RPG variable (i.e. RXS_VAR). If you were creating // the document in the IFS (which should be done if it is bigger than 65535) you would // specify RXS_STMF for the first parameter and then specify the file name/location in // the second parameter. // // The third parm can be replaced with a code page you want the IFS // file to be created as. The default will be fine is most cases. The fourth and fifth // parms allow you to temporarily specify different template and transaction // directories. For instance maybe you want to put your templates in // /mycompany/templates/ and put transactions in /mycompany/transactions/. The last // parameter is telling the template engine to be in debug mode which will place // helpful information into the job log for debugging purposes. // // RXS_loadTpl is bringing an IFS template file into the Template Engine to be used // later on with calls to RXS_updVar and RXS_wrtSection. Note that the relative // location of geturi2.tpl is used instead of a full qualified path because geturi2.tpl // is located in the default template directory of /www/myrxs/templates/. The default // template directory is configured in DB2 table RXSCFG located in MYRXS (or whatever // your environment name may be). // // RXS_updVar is replacing the variable placeholder in the template // (i.e. .:fahrenheit:.) with %char(100). // // RXS_wrtSection is taking the section specified in quotes and writing it to memory. // In this case there is only one section being written out which is 'CONTENT'. // // The on-error clause is monitoring for an errors that occur and will place the error // in variable gError. //------------------------------------------------------------------------------------------- begsr compose; monitor; RXS_initTplEng(RXS_VAR: *omit: *omit: *omit: *omit: *on); RXS_loadTpl('geturi2.tpl'); RXS_updVar('fahrenheit': %char(100)); RXS_wrtSection('CONTENT'); gReqData = RXS_getBuffData(*on); //*on=clear buffer after retrieving. on-error; gError = RXS_catchError(); endmon; endsr; //------------------------------------------------------------------------------------------- //@Author: Kato Integrations //@Desc: This sub procedure will take the SOAP XML request created with the Template Engine // in sub proc compose() and transmit it to the end point (say web service). // The API to be used here is RXS_getUri. Before RXS_getUri can be called it must // be primed with the information necessary to appropriate invoke the web service. // // gInCfg.URI is the qualified http location of the web service to be invoked. // // gInCfg.Nbr is stating the number of additional http headers that need to be sent // to the web service. In this case only one needs to be sent - 'SOAPAction'. // // gInCfg.UsrHdr is the name of the http header that is to be sent - 'SOAPAction'. // // gInCfg.UsrHdrDta is the value of the http header that is to be sent - // "http://tempuri.org/FahrenheitToCelsius". // // RXS_getUri is invoking the web service with the data contained within gInCfg. // gReqData contains the XML request that will be sent to the web service. // gRspData contains the response from the remote web service. // gRspHttpHdr will contain the http headers sent back from the web services server. //------------------------------------------------------------------------------------------- begsr transmit; monitor; gInCfg.URI = 'http://www.w3schools.com/webservices/tempconvert.asmx'; gInCfg.NbrHdrs = 1; gInCfg.UsrHdr(1) = 'SOAPAction'; gInCfg.UsrHdrDta(1) = '"http://tempuri.org/FahrenheitToCelsius"'; RXS_getUri(gInCfg: gReqData: gRspData: gRspHttpHdr); on-error; gError = RXS_catchError(); endmon; endsr; //------------------------------------------------------------------------------------------- //@Author: Kato Integrations //@Desc: This sub procedure is used to prep and invoke the parser with the appropriate // information. // // RXS_allElemContentHandler is telling the parser your program wants to be notified of // all parsing events involving element content. A procedure pointer is required that // tells the parser which local sub procedure to call when it finds element content. // // RXS_parse is telling the parser to start parsing the document. The first parm is // specifying the variable contents to be parsed and the second parm is stating the // value in the first parm is indeed a variable. RXS_parse also has the ability to // parse an IFS files contents containing XML so that is why the second parm is needed // to declare what is contained in the first parm. The third parm is telling the // parser what local sub procedure to call in the event it encounters invalid xml. //------------------------------------------------------------------------------------------- begsr parse; monitor; RXS_ignElemNamSpc('/Envelope'); RXS_ignElemNamSpc('/Envelope/Body'); RXS_allElemContentHandler( %paddr(allHandler) ); RXS_parse(gRspData: RXS_VAR: %paddr(errHandler)); on-error; gError = RXS_catchError(); endmon; endsr; /end-free //------------------------------------------------------------------------------------------- //@Author: Kato Integrations //@Desc: This is the local sub procedure specified on RXS_allElemContentHandler. This sub // procedure will get called by the parser each time element content is encountered. // Each time this sub procedure is called there will be information passed so we know // exactly what the parser found and where it found it. // //@Notes: There are four events that your program can be notified of through the allHandler // sub procedure and they are passed in the pEvntType parm. An event is triggered // as the parser reads the document top down, left to right (same way you read the // newspaper). Note that you will only be notified of events you specified before the // call to RXS_parse by using API's RXS_allElemBegHandler, RXS_allElemContentHandler, // RXS_allElemEndHandler, and RXS_allAttrHandler. // // The four events and their values (note that these can all be overidden by // changing the RXSCFG file or by doing a temporary override on the RXS_parse command) // // Element Begin = '>' -- Placed at end of string (i.e. '/elem>') // Element Content = '/' -- Placed at end of string (i.e. '/elem/') // Element End = '/>' -- Placed at end of string (i.e. '/elem/>') // Attribute = '@' -- Placed between the elem and attr (i.e. '/elem@attr') // // The most common events you will use are Element Content and Attribute simply // because these are the two that provide business data via the pData parm on the // allHandler procedure interface. Events Element Begin and Element End are very // helpful when you have repeating XML data. You can then use the Begin and End // events to do a CLEAR and WRITE to a PF record respectively. Remember that // in-between the Element Begin and Element End events you will be notified of all the // element content, which means that after the CLEAR (i.e. Element Begin event) you // can place data into the PF record until you reach the Element End event at which // time you can do a WRITE of that record because it has now been populated with data. //------------------------------------------------------------------------------------------- P allHandler b D allHandler pi D pEvntType value like(RXS_Type) D pXPath value like(RXS_XPath) D pData value like(RXS_XmlData) D pDataLen value like(RXS_Length) /free //This 'if' statement is checking to see if the pXPath variable contains the element we //are looking for. A value of '/' at the end of FahrenheitToCelsiusResult signifies we are //looking for the element content of . If we were looking to //be notified of the beginning element we would specify //'...CelsiusResult>', and in a similar manner if we wanted to be notified of the ending // we would specify '...CesiusResult/>'. //Because we chose to ignore name spaces for /Envelope and /Envelope/Body by using the //RXS_ignElemNamSpc API means we don't have to specify the name space (i.e. soapenv:) //in the below XPath comparison. If we would not have used the RXS_ignElemNamSpc API //above the 'if' statement would need to look like the following: // //if pXPath = // '/soapenv:Envelope/soapenv:Body/FahrenheitToCelsiusResponse' + // '/FahrenheitToCelsiusResult/'; // //That isn't that big of a deal until you realize that the value of //'soapenv' can change from one language to the next. Java traditionally uses 'SOAP-ENV' //as the namespace which would break the parsing code unless we chose to ignore the //namespaces by using RXS_ignElemNamSpc. if pXPath = '/Envelope/Body/FahrenheitToCelsiusResponse' + '/FahrenheitToCelsiusResult/'; gCelciusValue = RXS_charToNbr(pData: 0); endif; /end-free P e //------------------------------------------------------------------------------------------- //@Author: Kato Integrations //@Desc: If an error occurs durning the parsing of xml then this sub procedure will be // called by the xml parser. An example of an error would be un-matched begin and end // tags. In this case the gError data structure variable is being occupied with the // appropriate info so the mainline of this program knows that normal processing // should not continue. //------------------------------------------------------------------------------------------- P errHandler B D errHandler PI D pCurLine 10i 0 value D pCurCol 10i 0 value D pErrStr 1024a value varying /free gError.code = 'GETURI2001'; gError.severity = 100; gError.pgm = 'GETURI2.errHandler'; gError.text = 'Line:' + %char(pCurLine) + ' Col:' + %char(pCurCol) + ' ' + pErrStr; /end-free P E ``` ## Template File ```xml ::CONTENT .:fahrenheit:. ``` ## Sample XML Request ```xml 100 ``` ## Sample XML Response ```xml 38 ``` --- # Call Non-SOAP Web Service > RPG-XML Suite 2.x example composing and transmitting a simple XML request to a non-SOAP web service using templates and RXS_getUri(). Compose a simple xml stream for a non-SOAP web service transaction. It will call web service http://[AS400_IP]:8181/myrxs/rxs3 which is included in the base install of the RPG-XML Suite. Note the [AS400_IP] address will need to be changed to that of the machine where RPG-XML Suite was installed. ## Source Code ```rpgle //******************************************************************************************* //@Author - Kato Integrations //@Desc: Compose a simple xml stream for a non-SOAP web service transaction. It will // call web service http://[AS400_IP]:8181/myrxs/rxs3 which is included in // the base install of the RPG-XML Suite. Note the [AS400_IP] address will need to be // changed to that of the machine where RPG-XML Suite was installed. //@Notes: //******************************************************************************************* H dftactgrp(*no) bnddir('RXSBND') /copy rxs,RXSCp RXS_* procedures & definitions // //Local Prototypes // 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) D errHandler pr D pCurLine 10i 0 value D pCurCol 10i 0 value D pErrStr 1024a value varying D gError ds likeds(RXS_Error) inz //Result of parse D gPrsData ds qualified inz D status 10a varying D msg 256a varying //Used for RXS_getUri API D gInCfg ds likeds(RXS_GetUriIn) inz D gReqData s like(RXS_XmlData) D gRspData s like(RXS_XmlData) D gRspHttpHdr s like(RXS_XmlData) /free reset gError; reset gPrsData; exsr compose; if gError.code <> *blanks; return; endif; exsr transmit; if gError.code <> *blanks; return; endif; exsr parse; RXS_log(RXS_DIAG: 'gPrsData.status=' + gPrsData.status); RXS_log(RXS_DIAG: 'gPrsData.msg=' + gPrsData.msg); *inlr = *on; begsr compose; monitor; RXS_initTplEng(RXS_VAR: *omit: *omit: *omit: *omit: *on); RXS_loadTpl('geturi3.tpl'); RXS_updVar('residential': 'true'); RXS_updVar('title': 'Mr.'); RXS_updVar('first': 'Sample'); RXS_updVar('last': 'Resident'); RXS_updVar('street': '123 Center Rd'); RXS_updVar('cty': 'Mankato'); RXS_updVar('state': 'MN'); RXS_updVar('zip': '56001'); RXS_wrtSection('PostAdr_begin'); RXS_updVar('phone': '123-123-1234'); RXS_wrtSection('phone'); RXS_updVar('phone': '321-321-4321'); RXS_wrtSection('phone'); RXS_wrtSection('PostAdr_end'); gReqData = RXS_getBuffData(*on); //*on=clear buffer after retrieving. on-error; gError = RXS_catchError(); endmon; endsr; begsr transmit; monitor; //Note the below IP address needs to be changed to that of the iSeries where //the RPG-XML Suite was installed. Also note that if a different value was used //for the name of the RXS instance than 'myrxs' that should be specified in the //below URL. gInCfg.URI = 'http://192.168.0.11/myrxs/rxs3'; gInCfg.Port = 8181; gInCfg.Debug = RXS_YES; RXS_getUri(gInCfg: gReqData: gRspData: gRspHttpHdr); on-error; gError = RXS_catchError(); endmon; endsr; begsr parse; monitor; RXS_allElemContentHandler(%paddr(allHandler)); RXS_allAttrHandler(%paddr(allHandler)); RXS_parse(gRspData: RXS_VAR: %paddr(errHandler)); on-error; gError = RXS_catchError(); endmon; endsr; /end-free //------------------------------------------------------------------------------------------- //@Author: Kato Integrations //@Desc: //@Notes: There are four events that your program can be notified of through the allHandler // sub procedure and they are passed in the pEvntType parm. An event is triggered // as the parser reads the document top down, left to right (same way you read the // newspaper). Note that you will only be notified of events you specified before the // call to RXS_parse by using API's RXS_allElemBegHandler, RXS_allElemContentHandler, // RXS_allElemEndHandler, and RXS_allAttrHandler. // // The four events and their values (note that these can all be overidden by // changing the RXSCFG file or by doing a temporary override on the RXS_parse command) // // Element Begin = '>' -- Placed at end of string (i.e. '/elem>') // Element Content = '/' -- Placed at end of string (i.e. '/elem/') // Element End = '/>' -- Placed at end of string (i.e. '/elem/>') // Attribute = '@' -- Placed between the elem and attr (i.e. '/elem@attr') // // The most common events you will use are Element Content and Attribute simply // because these are the two that provide business data via the pData parm on the // allHandler procedure interface. Events Element Begin and Element End are very // helpful when you have repeating XML data. You can then use the Begin and End // events to do a CLEAR and WRITE to a PF record respectively. Remember that // in-between the Element Begin and Element End events you will be notified of all the // element content, which means that after the CLEAR (i.e. Element Begin event) you // can place data into the PF record until you reach the Element End event at which // time you can do a WRITE of that record because it has now been populated with data. //------------------------------------------------------------------------------------------- P allHandler b D allHandler pi D pEvntType value like(RXS_Type) D pXPath value like(RXS_XPath) D pData value like(RXS_XmlData) D pDataLen value like(RXS_Length) /free select; when pXPath = '/response@status'; gPrsData.status = pData; when pXPath = '/response/'; gPrsData.msg = pData; endsl; /end-free P e //------------------------------------------------------------------------------------------- //@Author: Kato Integrations //@Desc: //------------------------------------------------------------------------------------------- P errHandler B D errHandler PI D pCurLine 10i 0 value D pCurCol 10i 0 value D pErrStr 1024a value varying /free gError.code = 'GETURI3001'; gError.severity = 100; gError.pgm = 'GETURI3.errHandler'; gError.text = 'Line:' + %char(pCurLine) + ' Col:' + %char(pCurCol) + ' ' + pErrStr; /end-free P E ``` ## Template File ```xml ::PostAdr_begin .:first:. .:last:. .:street:. .:cty:. .:state:. .:zip:. ::phone .:phone:. ::PostAdr_end ``` ## Sample XML Request ```xml Egan Jones 123 Fake Street Mankato MN 56001 222-444-5555 ``` ## Sample XML Response ```xml Postadr for Egan Jones has been processed. ```