The XMLi package offers two different methods for generating XML.
XMLi1 enables the building of XML within RPG using procedure calls. Data can be written to your program variables or pointers.
XMLi2 provides an XML-based scripting language that makes XML generation easy. Simply write a template of your desired XML/HTML and use imbedded SQL queries to build your data. Pass parameters to the template from your RPG to be used in your SQL queries. Conditional logic is provided by IF and CHOOSE blocks, and looping constructs are provided by DOW/DOU/FOR loops. Looping through SQL queries is provided using FOR-EACH. Data can be written to the IFS, standard output, or passed to a call-back procedure.
In this post we’ll take one simple XML document, and we will generate the same using XMLi1
<Customers>
<RecordCount>12</RecordCount>
<Customer ID="938472">
<Name>Henning</Name>
<Address>
<Street>4859 Elm Ave</Street>
<City>Dallas</City>
<State>TX</State>
<Zip>75217</Zip>
</Address>
</Customer>
</Customer>
In This Example we will Be Using QCUSTCDT - PC Support Customer File from QIWS library,
Beginning at (a) in the following code, we identify the binding directory supplied with XMLi to make it easy for the compiler to locate XMLi's subprocedures. This way a simple CRTSQLRPGI (or CRTBNDRPG if we weren’t using embedded SQL) can be used to compile the program.
(b) includes the XMLi prototypes in the program.
(c) defines xmlData, the field to hold the generated XML document, followed by xmlFilename, the name of the file to which it will be written.
(a) H BNDDIR('XMLILIB/XMLI') DftActGrp(*no)
(b) /include XMLILIB/QRPGLESRC,XMLI_H
// Declare field definitions for use by SQL
d customer E DS ExtName('QIWS/QCUSTCDT')
// Work Variables
d recordCount s 5i 0
d endOfData c '02000'
(c) d xmlData s 10000a Inz
d xmlFilename s 128a Varying
d Inz('/Partner400+
d /CustomersE1.xml')
In the following logic, the call to xmli_useVariable() at (d) identifies the variable in which XMLi is to build the XML document. You can either specify a variable as we’ve done, or have XMLi provide “managed memory” automatically for you.
We next (e) set the format for the generated XML. The PRETTY option causes the XML to be indented to make it easier to read and is a good option to use when testing. For production purposes, you might want to use SIMPLE (no indentation). Other options are available when using the XMLi2 templating approach.
/Free
(d) xmli_useVariable(xmlData);
(e) xmli_setFormat(XML_FORMAT_PRETTY);
Exec SQL
select count(*)
into :recordCount
from qiws/qcustcdt
where STATE = 'TX';
Now we begin the process of generating the actual XML. At (f), we call the xmli_openTag() API to generate the <Customers> tag. Then (g) calls xmli_addElement() to generate the complete <RecordCount> nnn </RecordCount> element.
The actual SQL directives (h) set up the cursor so that we can subsequently loop through the result set. The actual loop begins at (i) in the next code example.
(f) xmli_openTag('Customers');
(g) xmli_addElement('RecordCount': %char(recordCount));
(h) Exec SQL
declare customerCursor cursor for
select CUSNUM, LSTNAM, STREET, CITY, STATE, ZIPCOD
from QIWS.QCUSTCDT
where STATE = 'TX';
Exec SQL
open customerCursor;
Now that all the setup is complete, we can loop through the result set and build the body of the XML document. This process begins at (j) where we create the opening tag for the <Customer> complex element. Since the Customer element includes the attribute ID, we need to call xmli_addAttribute() to add the attribute value (k). xmli_addAttribute always adds the attribute to the last element opened, so the sequence is important here.
We then proceed to add all of the individual simple elements before finally at (l) using the xmli_closeTag() API to close out the Address and Customer elements.
Once all rows in the result set have been processed, we can proceed to close the Customers element (m) and then call the API xmli_writeToFileWithVar() to write the XML document that has been built in the xmlData variable to the IFS file named in the xmlFilename variable.
(i) DoU SQLSTATE = endOfData;
Exec SQL
fetch next
from customerCursor
into :CUSNUM, :LSTNAM, :STREET, :CITY,
:STATE, :ZIPCOD;
If SQLSTATE <> endOfData;
(j) xmli_openTag('Customer');
(k) xmli_addAttribute('ID': %char(cusnum));
xmli_addElement('Name': LSTNAM);
xmli_openTag('Address');
xmli_addElement('Street': STREET);
xmli_addElement('City': CITY);
xmli_addElement('State': STATE);
xmli_addElement('Zip': %editc(ZIPCOD:'X'));
(l) xmli_closeTag('Address');
xmli_closeTag('Customer');
EndIf;
EndDo;
Exec SQL
close customerCursor;
(m) xmli_closeTag('Customers');
xmli_writeToFileWithVar( xmlFilename
: xmlData
: XML_ENCODING_UTF8);