Program: GETURI3A
//*******************************************************************************************
// @Author - Aaron Bartell
// @Desc: Compose a simple xml stream for a non-SOAP web service transaction. It will
// call web service http://192.168.0.11:8181/myrxs/rxs3 which is included in
// the base install of the RPG-XML Suite. Note the IP address will need to be
// changed to that of the machine where RPG-XML Suite was installed.
// @Notes: This program uses IFS files for the request and response.
//*******************************************************************************************
H dftactgrp(*no) bnddir('RXSBND')
/copy rxs,RXSCp
D compose pr
D transmit pr
D parse pr
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 gRspHttpHdr s like(RXS_XmlData)
D gUId s 15 0
D gReqFile s like(RXS_FilePath)
D gRspFile s like(RXS_FilePath)
/free
reset gError;
reset gPrsData;
// Setup unique file names for IFS files
// The next 3 lines of code setup unique file names for the
// IFS files that are going to be created for the request and
// response. RXS_nextUnqNbr creates a unique number which
// RXS_cmpTransFile will append to the end of the file names.
gUID = RXS_nextUnqNbr();
gReqFile = RXS_cmpTransFile('_': '.xml': 'geturi3a_req': %char(gUID));
gRspFile = RXS_cmpTransFile('_': '.xml': 'geturi3a_rsp': %char(gUID));
compose();
if gError.code <> *blanks;
return;
endif;
transmit();
if gError.code <> *blanks;
return;
endif;
parse();
RXS_log(RXS_DIAG: 'gPrsData.status=' + gPrsData.status);
RXS_log(RXS_DIAG: 'gPrsData.msg=' + gPrsData.msg);
*inlr = *on;
/end-free
//--------------------------------------------------------------------------------------------
// @Author: Aaron Bartell
// @Desc:
//--------------------------------------------------------------------------------------------
P compose b
D compose pi
/free
monitor;
// The next two lines of code determine which template will be
// used to compose the request. RXS_initTplEng sets up the
// template engine, the first parm specifies where the output
// will go (in our case it's a STMF), the second parm specifies
// the name of the STMF to be written, and the third parm specifies
// the CCSID used to create the file. RXS_loadTpl then loads the
// IFS template file to be used to compose the XML.
RXS_initTplEng(RXS_STMF: gReqFile: 819: *omit: *omit: *on);
RXS_loadTpl('geturi3.tpl');
RXS_updVar('residential': 'true');
RXS_updVar('title': 'Mr.');
RXS_updVar('first': 'Aaron');
RXS_updVar('last': 'Bartell');
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');
// When writing to IFS files be sure to specify *on as the second
// PARM on your LAST RXS_wrtSection instruction. This will clear
// the buffer and guarantee that all the information gets written
// to the IFS file.
RXS_wrtSection('PostAdr_end':*on);
on-error;
gError = RXS_catchError();
endmon;
/end-free
P e
//--------------------------------------------------------------------------------------------
// @Author: Aaron Bartell
// @Desc:
//--------------------------------------------------------------------------------------------
P transmit b
D transmit pi
/free
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;
// When using IFS files it is necessary to specify the REQTYPE as well as the
// STMF name (ReqSTMF). By default RXS assumes you want to use RPG variables
// to store the request and response XML.
gInCfg.ReqType = RXS_STMF;
gInCfg.ReqStmf = gReqFile;
gInCfg.RspType = RXS_STMF;
gInCfg.RspStmf = gRspFile;
gInCfg.Debug = RXS_YES;
// When using IFS files the 2nd & 3rd Parms should be *Omit on the RXS_getURI API
// because we aren't using RPG variables to hold the XML.
RXS_getUri(gInCfg: *Omit: *Omit: gRspHttpHdr);
on-error;
gError = RXS_catchError();
endmon;
/end-free
P e
//--------------------------------------------------------------------------------------------
// @Author: Aaron Bartell
// @Desc:
//--------------------------------------------------------------------------------------------
P parse b
D parse pi
/free
monitor;
RXS_allElemContentHandler(%paddr(allHandler));
RXS_allAttrHandler(%paddr(allHandler));
// We are receiving our response file into the IFS and use the API
// RXS_parse to parse that file. The first parm specifies the
// name of the file in the IFS that we are parsing, the second parm
// identifies it as a STMF, and the third parm specifies the name
// of the procedure to be called in case of a parsing error.
RXS_parse(gRspFile: RXS_STMF: %paddr(errHandler));
on-error;
gError = RXS_catchError();
endmon;
/end-free
P e
//--------------------------------------------------------------------------------------------
// @Author: Aaron Bartell
// @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: Aaron Bartell
// @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 = 'GETURI3A.errHandler';
gError.text =
'Line:' + %char(pCurLine) +
' Column:' + %char(pCurCol) +
' ' + pErrStr;
/end-free
P E
IFS Template: /www/myrxs/templates/geturi3.tpl
::PostAdr_begin
<PostAdr residential=".:residential:.">
<name title=".:title:.">
<first>.:first:.</first>
<last>.:last:.</last>
</name>
<street>.:street:.</street>
<cty>.:cty:.</cty>
<state>.:state:.</state>
<zip>.:zip:.</zip>
::phone
<phone>.:phone:.</phone>
::PostAdr_end
</PostAdr>