Consuming XML Documents
This article series covers the basics of using XML as a communications medium within RPG applications: writing programs that produce XML documents, writing programs that consume XML documents, and getting those documents from one program to the other. The first article was an introduction to XML and how to create XML documents. This one will focus on how to consume those documents.
Picking Up Where We Left Off
In the introduction, I presented two options for generating XML: the brute force method of programming every tag yourself and the markup-based technique of CGIDEV2, the freely available toolkit from Giovanni Perotti. While CGIDEV2 was intended originally to help create CGI programs, it’s become a favorite tool for XML development in the IBM i community and I highly recommend it for anybody doing anything but the most trivial XML. CGIDEV2 uses templates, and those templates are most easily built using an XML authoring tool.
In article 1, the idea was to generate this request:
Using this template:
<?xml version="1.0" encoding="UTF-8"?>
<!-- $BalanceRequest -->
I included a simple RPG program, but it stopped short of actually creating the XML document. I had two choices: either generate the XML into a temporary buffer and pass that to the consuming program, or generate a document in the IFS and pass the name of the document. Since this article focuses on consuming the XML, I’ll take the simplest approach and add the handful of lines of code that lets me pass the buffer containing the generated XML directly another program. Here’s the entire program, with the code required to call another program (and some comments added to help break up the D-specs):
h option(*srcstmt:*nodebugio) dftactgrp(*no) bnddir('CGIDEV2')
* CGIDEV2 prototype and definitions
d C_XML_PATH c '/XMLGen/'
d C_XML_TEMPLATE c 'BalanceRequestTemplate.xml'
d C_XML_SECID1 c ''
d C_SEC_BALREQ c 'BalanceRequest'
*NEW d XmlBuffer ds qualified
*NEW d ptr *
*NEW d len 10u 0
* External prototype
*NEW d PRCBALREQ pr extpgm('PRCBALREQ')
*NEW d BufPtr *
*NEW d BufLen 10u 0
* Mainline prototype
d REQBAL pr extpgm('REQBAL')
d iItem 32
d iQty 10 2
d REQBAL pi
d iItem 32
d iQty 10 2
// Open and parse template
GetHTMLIFS(C_XML_PATH + C_XML_TEMPLATE: C_XML_SECID1: C_XML_SECID2);
// Populate variables and write a section to the buffer
updHTMLvar( 'Item': iItem);
updHTMLvar( 'Quantity': %char(iQty));
*NEW // Get buffer pointer & length, pass to the processing program
*NEW XmlBuffer = GetHtmlBufferP();
*NEW PRCBALREQ( XmlBuffer.ptr: XmlBuffer.len);
*inlr = *on;
The added lines have the word *NEW at the beginning. The first new lines define XmlBuffer, a qualified data structure used to receive the location and length of the generated XML. The data structure contains two parameters: a pointer and a length. The prototype for the XML consumer, PRCBALREQ (PRoCess BALance REQuest), conveniently takes as parameters a pointer and a length. Finally, I add the actual program logic, which consists of a call to the CGIDEV2 function GetHtmlBufferP to load the XmlBuffer data structure followed by a call to PRCBALREQ passing the pointer and length that was just returned. Nothing to it!