Receiving XML data into an RPG program data structure






Here are several examples of xml-into. xml-into is RPG's native method of mapping an XML file directly into a field or data structure. Each example is an enhancement of the previous one, illustrating basic techniques using xml-into.


Example 1 - xml-into - define input and output directly in program
Example 2 - xml-into - define input from IFS
Example 3 - xml-into - define input and output externally
Example 4 - xml-into - define input and output externally with Multiple occurring data elements
xml-into - Long XML element names


Example 1: xml-into example - define input and output directly in program

In this example, we map XML string contained in variable myXML to a data structure called outDs. A variable called options contains a list of processing parameters. In the example below, we are using the path and case options. More on these below.

      *----------------------------------------------------------------------------                
      *  Simple example of XML-INTO processing in AS/400 RPG                                       
      *----------------------------------------------------------------------------                
      *   xml-into options:                                                                        
      *                                                                                            
      *   path=CPUROOT            -  this is the root path element in XML document, not a file name!
      *   case=any                -  instructs parser to ignore case
      *                                                                                            
     D* myXML string represents incoming XML string                                                
     D myXML           S            200A                                                           
     D                                                                                             
     D* outDS is data structure that receives XML string                                           
     D outDS           DS                                                                          
     D Activite                     100A         ALIAS(ACTIVATE__ALLOWS_30_CHARS_LONG)                                          
     D NoIncApc                     100A                                                  
     D NoIncCPU                     100A                                                  
     D AddNoEmp                     100A                                                  
     D Code                         100A                                                  
     D                                                                                             
     D* options that control how the XML document is to be interpreted and parsed.                 
     D options         s            100a   varying                                                 

      /free                                                                                        
          Eval options = 'path=CPUROOT +                                                             
                          case=any';                                                               

          // here we define the XML in the code... an illustrative but not a very realistic scenario
          Eval myXML = '<CPUROOT>'+                                                               
                          '<Activite>broken cable</Activite>'+                                     
                          '<NoIncApc>INC260454</NoIncApc>'+                                        
                          '<NoIncCPU>24669</NoIncCPU>'+                                            
                          '<AddNoEmp>073</AddNoEmp>'+                                              
                          '<Code>INF</Code>'+                                                      
                        '</CPUROOT>';                                                                

          // map myXML into outDS
          xml-into outDS %XML(myXML:options);                                                      

          Eval *inlr = *on;                                                                        
          Return; 
      /end-free   



If we retrieve the value of data structure outDS after the xml-into has successfully processed, we should see that XML values have to retrieved into appropriate fields.



%XML Options Parameters
Parameter
Description
doc
The doc option specifies whether the first parameter of the %XML built-in function has an XML document, or has the name of a file containing the XML document. Example:
doc=string
doc=file
case
This specifies how the XML is stored. Specifying case=lower or case=upper is faster than case=any because the parser will convert the XML to all uppercase when case=any is specified.
trim
This controls whether spaces (tabs, linefeeds, excess blanks) should be removed before assigning to variables. It applies only to character fields. Other data types always trim extra spaces.
allowmissing    
When you copy the XML values to a data structure, this option controls whether or not a node/element for each data structure subfield must exist in the XML. You probably want to set this to "yes" unless you are sure that all node/elements are mandatory.
allowextra
The opposite of allowmissing, this option controls whether or not to allow extra nodes/elements in the XML that do not have a corresponding subfield name in the target data structure.
path
The path parameter allows you to directly retrieve an element in an XML document. If this option is not specified, the element retrieved is the same as the target field name (for standalone fields) and the names of the subfields (for data structures). For example, in these examples you we specify the CPUROOT element and it's child elements. If wanted only the NoIncCPU element, we would specify CPUROOT/NoIncCPU

 <CPUROOT>
   <Activite>broken cable</Activite>
   <NoIncApc>INC260454</NoIncApc>
   <NoIncCPU>24669</NoIncCPU>
   <AddNoEmp>073</AddNoEmp>
   <Code>INF</Code>
</CPUROOT>

Note that later versions of OS/400 have added additional parameters including ccsid, data subfield and count prefix options.



Example 2: xml-into example - define input from IFS

In this example, we retrieve our XML from an external file on the iSeries IFS called /tmp/xml-test.xml.

      *----------------------------------------------------------------------------                
      *  Simple example of XML-INTO processing in AS/400 RPG                                       
      *----------------------------------------------------------------------------                
      *                                                                                            
      *   XML-Into options:                                                                        
      *                                                                                            
      *   path=CPUROOT          -  root path in XML document                                       
      *   case=any              -  case insensitive                                                
      *   allowextra=yes        -  ignore extra XML elements                                       
      *   allowmissing=yes      -  allow missing XML elements                                      
      *   doc=file              -  XML source is from IFS, if not specified then program
      *                            assumes doc=string
      *   case=convert          -  IBM added this switch to map special characters (accents)
      *                            back to basic latin alphabet - available only in V7
      *                                  
     D* outDS is data structure that receives XML string                                           
     D outDS           DS                                                                          
     D Activite                     100A                                                  
     D NoIncApc                     100A                                                  
     D NoIncCPU                     100A                                                  
     D AddNoEmp                     100A                                                  
     D Code                         100A                                                  

     D* options that control how the XML document is to be interpreted and parsed.                 
     D options         s            100a   varying                                                 
                                                                                                   
      /free                                                                                        
                                                                                                   
          Eval options = 'path=CPUROOT +                                                             
                          case=any +                                                               
                          allowextra=yes +                                                         
                          allowmissing=yes +                                                       
                          doc=file';                                                               
                                                                                                   
          // here we read from IFS file /tmp/xml-test.xml and put data into data structure called outDS
  xml-into outDS %XML('/tmp/xml-test.xml':options);                                        
                                                                                                   
          Eval *inlr = *on;                                                                        
          Return;                                                                                  
                                                                                                   
      /end-free                                                                                    



Example 3: xml-into example - define input and output externally

External PF file used for data structure

A* FILE: CM9999B1                                                        
A          R CM9999B1RC                                                  
A            ACTIVITE     100A                                           
A            NOINCApc     100A                                           
A            NOINCCPU     100A                                           
A            ADDNOEMP     100A                                           
A            CODE         100A                                           

RPG file

       *----------------------------------------------------------------------------                
      *  Simple example of XML-INTO processing in AS/400 RPG                                       
      *  xml-into example - define input and output externally                                                       
      *----------------------------------------------------------------------------                
      *                                                                                            
      *   XML-Into options:                                                                        
      *                                                                                            
      *   path=CPUROOT            -  root path in XML document                                       
      *   case=any              -  case insensitive                                                
      *   allowextra=yes        -  ignore extra XML elements                                       
      *   allowmissing=yes      -  allow misisng XML elements                                      
      *   doc=file              -  XML source is from IFS, if not specified then program
      *                            assumes doc=string
      *   case=convert          -  IBM added this switch to map special characters (accents)
      *                            back to basic latin alphabet - available only in V7
      *                                  
      *  Header data definitions data structure                                                    
     D MyXMLDS       E DS                  EXTNAME(CM9999B1)                                       
     D                                     qualified                                               

     D* options that control how the XML document is to be interpreted and parsed.                 
     D options         s            100a   varying                                                 

      /free                                                                                        

          Eval options = 'path=CPUROOT +                                                             
                          case=any +                                                               
                          allowextra=yes +                                                         
                          allowmissing=yes +                                                       
                          doc=file';                                                               

          xml-into MyXMLDS %XML('/tmp/xml-test.xml':options);                                      

          Eval *inlr = *on;                                                                        
          Return;                                                                                  

      /end-free                                                                                    

We may find that DDS's 10 character limitation of field names may not be appreciated by your trading partner. In this case you can use SQL to define tables.

 CREATE TABLE MYLIB/MYFILE
(                                   
Activite CHAR (100),                
NoIncApc CHAR (100),                
NoIncCPU CHAR (100),                
AddNoEmp CHAR (100),                
Code     CHAR (100)                 
NOT NULL WITH DEFAULT               
)                                   


Example 4: xml-into example - Multiple occurring data elements

So far we have seen a single occurance of an XML element. However, in the real world transactions rarely occur one at time... Orders, invoices, scripts come in batches and orders typically have more than one detail line. In order to accomadate this XML multiplicity, we will have to re-structure our XML a bit...

At left we have a XML file. It will pass basic XML validation as being "well formed", but will not give you results that you expect. Each value of "Activite" for instance, will over-right the previous one in your data structure. In the revision at right, we have added tag called <Incidents> and group each incident into a tag called <Incident> This structure will permit RPG to process all detail elements.

VALID
<CPUROOT>                                          
   
       <Activite>fix fan</Activite>              
       <NoIncApc>RT260454</NoIncApc>            
       <NoIncCPU>24669</NoIncCPU>                
       <AddNoEmp>073</AddNoEmp>                  
       <Code>INF</Code>                          
   
       <Activite>fix power supply</Activite>     
       <NoIncApc>RT260454</NoIncApc>            
       <NoIncCPU>24669</NoIncCPU>                
       <AddNoEmp>073</AddNoEmp>                  
       <Code>INF</Code>                          
   
</CPUROOT>                                       







BETTER
<CPUROOT>                                          
  <Incidents>                                    
 
    <Incident>                                   
       <Activite>fix fan</Activite>              
       <NoIncApc>RT260454</NoIncApc>            
       <NoIncCPU>24669</NoIncCPU>                
       <AddNoEmp>073</AddNoEmp>                  
       <Code>INF</Code>                          
     </Incident>                                 
                                                 
    <Incident>                                   
       <Activite>fix power supply</Activite>     
       <NoIncApc>RT260454</NoIncApc>            
       <NoIncCPU>24669</NoIncCPU>                
       <AddNoEmp>073</AddNoEmp>                  
       <Code>INF</Code>                          
     </Incident>                              

  </Incidents>                                      
</CPUROOT>                                       



Now we have done two simple things to our program below:
1) created a multiple occurring data structure by adding DIM(99) to MyXMLDS data structure
2) specified CPUROOT/Incidents/Incident as the root element.

By doing these two changes, xml-into will now capture up to 99 incidents in data structure MyXMLDS.

       *----------------------------------------------------------------------------                
      *  Example of XML-INTO processing in AS/400 RPG                                       
      *  xml-into example - multiple occurring XML elements
      *----------------------------------------------------------------------------                
      *                                                                                            
      *   XML-Into options:                                                                        
      *                                                                                            
      *   path=CPUROOT/Incidents/Incident  -  root path in XML document                                       
      *
      *                                  
      *  Header data definitions data structure                 
  *  Note in OS400 v7r1, IBM has added the ALIAS keyword on DDS defined Data Structures
      *  allowing us to go from 10 to 30 characters field names.  In the meantime, use can use SQL
  *  defined tables which permit really big field names
 
     D*MyXMLDS       E DS                  EXTNAME(CM9999B1)    ALIAS
D MyXMLDS       E DS                  EXTNAME(CM9999B1)    
     D                                     DIM(99)  
D                                     qualified                                               

     D* options that control how the XML document is to be interpreted and parsed.                 
     D options         s            100a   varying                                                 

      /free                                                                                        
                                                                   
         Eval options = 'path=CPUROOT/Incidents/Incident +               
                        case=any +                                    
                        allowextra=yes +                              
                        allowmissing=yes +                            
                        doc=file';                                    
                                                                   
         xml-into MyXMLDS %XML('/tmp/xml-test.xml':options);           
                                                                   
         Eval *inlr = *on;                                             
         Return;                                                       
                                                                   
     /end-free                                                         


Note how the path option in the xml-into statement points to the location in the XML file that you want to read into your data structure







Using long XML element names

Today I was asked if we are limited to 10 character tag names in our XML strings when reading into RPG. The answer is no, but the solution is not optimal. We can use long XML tag names, using the internally defined ("hardcoded") data structures, however as of V5r4, we cannot use long variable names using externally defined data structures.

Internally defined Data structure (DS)

D* outDS is data structure that receives XML string           
D outDS           DS                                          
D Activite                     100A    VARYING                
D Activite_1234567890_1234567890_1234567890_1234567890...     
D                              100A                           
D NoIncPJC                     100A    VARYING                
D NoIncCPU                     100A    VARYING                
D AddNoEmp                     100A    VARYING                
D Code                         100A    VARYING                

Raw XML data



Debug on DS outDS. Here we see long variable name and correct data.




In OS400 v7r1, IBM has added the ALIAS keyword on DDS defined Data Structures allowing us to go from 10 to 30 characters field names. Unfortunately this keyword does not apply in older versions of the OS.


A          R CM9999B1RC                                                     
A            ACTIVITE     100A         ALIAS(ACTIVATE__ALLOWS_30_CHARS_LONG) 
D*MyXMLDS       E DS                  EXTNAME(CM9999B1)    
D MyXMLDS       E DS                  EXTNAME(CM9999B1)    ALIAS


We can also create tables using SQL with long field names in v5r4. However RPG appears to mangle the long fields down to 10 characters values which effectively cuts our ability to use field names longer than 10 characters.


 CREATE TABLE MYLIB/CM9999B5(
ACTIVITE_1234567890_1234567890_1234567890_1234567890 CHAR (100) NOT NULL WITH DEFAULT,
ACTIVATE CHAR(100) NOT NULL WITH DEFAULT,                                                                    
NOINCPJC CHAR (100 ) NOT NULL WITH DEFAULT,                      
NOINCCPU CHAR (100 ) NOT NULL WITH DEFAULT,
ADDNOEMP CHAR (100 ) NOT NULL WITH DEFAULT,
CODE     CHAR (100 ) NOT NULL WITH DEFAULT
)   


IBM has been adding enhancements to its's XML offereing since v5r4.

For further reference you may want to visit:

  • IBM's Reference Guide to RPG IV, Section on xml-into
  • Many other good references and articles as indexed in Google.com