RESTXML

This example program demonstrates the basic structure of an RPG program utilizing RPG API Express to consume a REST based XML web service via HTTP GET, and parse the response XML with event-based parsing.

**FREE
Ctl-Opt ActGrp(*Caller) BndDir('RXSBND') Option(*NoDebugIO)
  Text('Ex - RESTXML');

/COPY QRPGLECPY,RXSCB

Dcl-Ds TransmitDS LikeDS(RXS_TransmitDS_t);
Dcl-Ds ParseDS LikeDS(RXS_ParseDS_t);
Dcl-Ds ErrorDS LikeDS(RXS_CatchThrowErrorDS_t);

Dcl-S XML Like(RXS_Var64Kv_t);
Dcl-S gNameList Like(RXS_Var64Kv_t);
Dcl-S gCount Int(10);

// Please note that the REST web service being consumed by this example program
//   is not 100% available due to metering being performed on the
//   "demo" account. Usually you can make multiple attempts over time and
//   get a proper response eventually.

monitor;

  // Transmit

  RXS_ResetDS( TransmitDS : RXS_DS_TYPE_TRANSMIT );
  TransmitDS.URI = 'http://api.geonames.org/cities'
                 + '?north=44.1&south=-9.9&east=-22.4'
                 + '&west=55.2&lang=de&username=demo';
  TransmitDS.LogFile = '/tmp/log.txt';
  TransmitDS.HTTPMethod = RXS_HTTP_METHOD_GET;
  XML = RXS_Transmit( *Omit : TransmitDS );

  // Parse

  reset gCount;
  reset gNameList;
  RXS_ResetDS( ParseDS : RXS_DS_TYPE_PARSE );
  ParseDS.GlobalHandler = %Paddr( XmlHandler );
  RXS_Parse( XML : ParseDS );

  // Output Parse Results as a Thrown Message

  RXS_ResetDS( ErrorDS : RXS_DS_TYPE_CATCHTHROWERROR );
  ErrorDS.MessageId = 'RXS9897';
  ErrorDS.MessageData = gNameList;
  ErrorDS.ThrowToCaller = RXS_YES;
  RXS_Throw( ErrorDS );

on-error;

  RXS_Joblog('Unexpected error occurred. See previous messages.');

endmon;

*INLR = *ON;
return;

Dcl-Proc XmlHandler;
  Dcl-Pi *N;
    pType Char(10) Value;
    pXPath VarChar(1024) Value;
    pData Pointer Value;
    pDataLen Int(10) Value;
  End-Pi;

  Dcl-S base VarChar(256);

  base = '/geonames/geoname';
  select;

    when pXPath = '/geonames/>';
      if gCount > 0;
        gNameList += 'No more names!';
      endif;

    when pXPath = base + '/toponymName>';
      gCount += 1;
      gNameList += %Char(gCount) + ': ';

    when pXPath = base + '/toponymName/>';
      gNameList += ', ';

    when pXPath = base + '/toponymName/';
      gNameList += RXS_STR( pData : pDataLen );

    // If the service is unavailable to the usage metering mentioned earlier,
    //   there will be XML data available for parsing per the below

    when pXPath = '/geonames/status@message';
      gNameList = RXS_STR( pData : pDataLen );

    when pXPath = '/geonames/status@value';
      gNameList += ' (' + RXS_STR( pData : pDataLen ) + ')';

  endsl;
End-Proc;
 
     H DFTACTGRP(*NO) ACTGRP(*CALLER) BNDDIR('RXSBND') OPTION(*NODEBUGIO)
     H TEXT('Fixed Format Ex - RESTXML')

      /COPY QRPGLECPY,RXSCB

     D XmlHandler      PR
     D  pType                        10A   Value
     D  pXPath                     1024A   Value Varying
     D  pData                          *   Value
     D  pDataLen                     10I 0 Value

     D TransmitDS      DS                  LikeDS(RXS_TransmitDS_t)
     D ParseDS         DS                  LikeDS(RXS_ParseDS_t)
     D ErrorDS         DS                  LikeDS(RXS_CatchThrowErrorDS_t)

     D XML             S                   Like(RXS_Var64Kv_t)
     D gNameList       S                   Like(RXS_Var64Kv_t)
     D gCount          S             10I 0

      /FREE

       // Please note that the REST web service being consumed by this example program
       //   is not 100% available due to metering being performed on the
       //   "demo" account.  Usually you can make multiple attempts over time and
       //   get a proper response eventually.

       monitor;

         // Transmit

         RXS_ResetDS( TransmitDS : RXS_DS_TYPE_TRANSMIT );
         TransmitDS.URI = 'http://api.geonames.org/cities'
                        + '?north=44.1&south=-9.9&east=-22.4'
                        + '&west=55.2&lang=de&username=demo';
         TransmitDS.LogFile = '/tmp/log.txt';
         TransmitDS.HTTPMethod = RXS_HTTP_METHOD_GET;
         XML = RXS_Transmit( *Omit : TransmitDS );

         // Parse

         reset gCount;
         reset gNameList;
         RXS_ResetDS( ParseDS : RXS_DS_TYPE_PARSE );
         ParseDS.GlobalHandler = %Paddr( XmlHandler );
         RXS_Parse( XML : ParseDS );

         // Output Parse Results as a Thrown Message

         RXS_ResetDS( ErrorDS : RXS_DS_TYPE_CATCHTHROWERROR );
         ErrorDS.MessageId = 'RXS9897';
         ErrorDS.MessageData = gNameList;
         ErrorDS.ThrowToCaller = RXS_YES;
         RXS_Throw( ErrorDS );

       on-error;

         RXS_Joblog('Unexpected error occurred. See previous messages.');

       endmon;

       *INLR = *ON;
       return;

      /END-FREE

     P XmlHandler      B
     D                 PI
     D  pType                        10A   Value
     D  pXPath                     1024A   Value Varying
     D  pData                          *   Value
     D  pDataLen                     10I 0 Value

     D base            S            256A   Varying
      /FREE

       base = '/geonames/geoname';
       select;

         when pXPath = '/geonames/>';
           if gCount > 0;
             gNameList += 'No more names!';
           endif;

         when pXPath = base + '/toponymName>';
           gCount += 1;
           gNameList += %Char(gCount) + ': ';

         when pXPath = base + '/toponymName/>';
           gNameList += ', ';

         when pXPath = base + '/toponymName/';
           gNameList += RXS_STR( pData : pDataLen );

         // If the service is unavailable to the usage metering mentioned earlier,
         //   there will be XML data available for parsing per the below

         when pXPath = '/geonames/status@message';
           gNameList = RXS_STR( pData : pDataLen );

         when pXPath = '/geonames/status@value';
           gNameList += ' (' + RXS_STR( pData : pDataLen ) + ')';

       endsl;

      /END-FREE
     P                 E