Creating an XML Parsing Subprocedure

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:

<PostAdr residential="true">
  <name title="Mr.">
    <first>Sample</first>
    <last>Resident</last>
  </name>
  <street>123 Center Rd</street>
  <cty>Mankato</cty>
  <state>MN</state>
  <zip>56001</zip>
  <phone>123-123-1234</phone>
  <phone>321-321-4321</phone>
</PostAdr>

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 place 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.


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:


D allHandler      pr
D  pType                              value like(RXS_Type)
D  pXPath                             value like(RXS_XPath)
D  pData                              value like(RXS_XmlData)
D  pDataLen                           value like(RXS_Length)


 //-----------------------------------------------------------------
 // @Author: 
 // @Created: 
 // @Desc:
 //-----------------------------------------------------------------
P allHandler      b
D allHandler      pi
D  pType                              value like(RXS_Type)
D  pXPath                             value like(RXS_XPath)
D  pData                              value like(RXS_XmlData)
D  pDataLen                           value like(RXS_Length)

D chgMe           s                   like(RXS_XmlData)
D baseEnv         s             70a   varying
 /free
   baseEnv = '/PostAdr';

   select;

   when pXPath = baseEnv +'/';
     chgMe = pData;
   when pXPath = baseEnv +'/name/';
     chgMe = pData;
   when pXPath = baseEnv +'/name/first/';
     chgMe = pData;
   when pXPath = baseEnv +'/name/last/';
     chgMe = pData;
   when pXPath = baseEnv +'/street/';
     chgMe = pData;
      ...
   endsl;
 /end-free
P                 e

It’s important to note that the code generated by BLDPRS will require some modifications to bring it in line with the new model for parsing subprocedures introduced in RXS3. The most important parts you’ll need to replace are the procedure prototype and interface. Additionally, because the parsing subprocedure utilizes pointers instead of native character fields, the subprocedure RXS_STR() must be used to convert. Below is what the above sample would look like modified to be compatible with RXS3.

Example Code

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


 //-----------------------------------------------------------------
 // @Author: 
 // @Created: 
 // @Desc:
 //-----------------------------------------------------------------
P XmlHandler      B
D XmlHandler      PI
D  pType                        10A   Value
D  pXPath                     1024A   Value Varying
D  pData                          *   Value
D  pDataLen                     10I 0 Value

D chgMe           S                   Like(RXS_Var1Kv_t)
D baseEnv         S             70a   varying
 /free
   baseEnv = '/PostAdr';

   select;

   when pXPath = baseEnv +'/';
     chgMe = RXS_STR( pData : pDataLen );
   when pXPath = baseEnv +'/name/';
     chgMe = RXS_STR( pData : pDataLen );
   when pXPath = baseEnv +'/name/first/';
     chgMe = RXS_STR( pData : pDataLen );
   when pXPath = baseEnv +'/name/last/';
     chgMe = RXS_STR( pData : pDataLen );
   when pXPath = baseEnv +'/street/';
     chgMe = RXS_STR( pData : pDataLen );
      ...
   endsl;
 /end-free
P                 E
D XmlHandler      PR
D  pType                        10A   Value
D  pXPath                     1024A   Value Varying
D  pData                          *   Value
D  pDataLen                     10I 0 Value


 //-----------------------------------------------------------------
 // @Author: 
 // @Created: 
 // @Desc:
 //-----------------------------------------------------------------
P XmlHandler      B
D XmlHandler      PI
D  pType                        10A   Value
D  pXPath                     1024A   Value Varying
D  pData                          *   Value
D  pDataLen                     10I 0 Value

D chgMe           S                   Like(RXS_Var1Kv_t)
D baseEnv         S             70a   varying
 /free
   baseEnv = '/PostAdr';

   select;

   when pXPath = baseEnv +'/';
     RXS_STR( chgMe : pData : pDataLen );
   when pXPath = baseEnv +'/name/';
     RXS_STR( chgMe : pData : pDataLen );
   when pXPath = baseEnv +'/name/first/';
     RXS_STR( chgMe : pData : pDataLen );
   when pXPath = baseEnv +'/name/last/';
     RXS_STR( chgMe : pData : pDataLen );
   when pXPath = baseEnv +'/street/';
     RXS_STR( chgMe : pData : pDataLen );
      ...
   endsl;
 /end-free
P                 E