How to handle variably repeating content in COBOL
In COBOL, you cannot process variably repeating content by using pointer arithmetic to address each instance of the data. Other programming languages do not have this limitation. This example shows you how to handle variably repeating content in COBOL for a Web service application.
This technique also applies to transforming XML to application
data using the TRANSFORM API commands. The following
example WSDL document represents a Web service with application data
that consists of an 8-character string that recurs a variable number
of times:
<?xml version="1.0"?>
<definitions name="ExampleWSDL"
targetNamespace="http://www.example.org/variablyRepeatingData/"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://www.example.org/variablyRepeatingData/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<types>
<xsd:schema targetNamespace="http://www.example.org/variablyRepeatingData/">
<xsd:element name="applicationData">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="component" minOccurs="1" maxOccurs="unbounded">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:length value="8"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
</types>
<message name="exampleMessage">
<part element="tns:applicationData" name="messagePart"/>
</message>
<portType name="examplePortType">
<operation name="exampleOperation">
<input message="tns:exampleMessage"/>
<output message="tns:exampleMessage"/>
</operation>
</portType>
<binding name="exampleBinding" type="tns:examplePortType">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="exampleOperation">
<soap:operation soapAction=""/>
<input><soap:body parts="messagePart" encodingStyle="" use="literal"/></input>
<output><soap:body parts="messagePart" encodingStyle="" use="literal"/></output>
</operation>
</binding>
</definitions>
Processing this WSDL document
through DFHWS2LS generates the following COBOL language structures:
03 applicationData.
06 component-num PIC S9(9) COMP-5 SYNC.
06 component-cont PIC X(16).
01 DFHWS-component.
03 component PIC X(8).
Note that the 8-character component
field
is defined in a separate structure called DFHWS-component
.
The main data structure is called applicationData
and
it contains two fields, component-num
and component-cont
.
The component-num
field indicates how many instances
of the component
data are present and the component-cont
field
indicates the name of a container that holds the concatenated list
of component
fields.The following COBOL code
demonstrates one way to process the list of variably recurring data.
It makes use of a linkage section array to address subsequent instances
of the data, each of which is displayed by using the
DISPLAY
statement:IDENTIFICATION DIVISION.
PROGRAM-ID. EXVARY.
ENVIRONMENT DIVISION.
DATA DIVISION.
WORKING-STORAGE SECTION.
* working storage variables
01 APP-DATA-PTR USAGE IS POINTER.
01 APP-DATA-LENGTH PIC S9(8) COMP.
01 COMPONENT-PTR USAGE IS POINTER.
01 COMPONENT-DATA-LENGTH PIC S9(8) COMP.
01 COMPONENT-COUNT PIC S9(8) COMP-4 VALUE 0.
01 COMPONENT-LENGTH PIC S9(8) COMP.
LINKAGE SECTION.
* a large linkage section array
01 BIG-ARRAY PIC X(659999).
* application data structures produced by DFHWS2LS
* this is normally referenced with a COPY statement
01 DFHWS2LS-data.
03 applicationData.
06 component-num PIC S9(9) COMP-5 SYNC.
06 component-cont PIC X(16).
01 DFHWS-component.
03 component PIC X(8).
PROCEDURE DIVISION USING DFHEIBLK.
A-CONTROL SECTION.
A010-CONTROL.
* Get the DFHWS-DATA container
EXEC CICS GET CONTAINER('DFHWS-DATA')
SET(APP-DATA-PTR)
FLENGTH(APP-DATA-LENGTH)
END-EXEC
SET ADDRESS OF DFHWS2LS-data TO APP-DATA-PTR
* Get the recurring component data
EXEC CICS GET CONTAINER(component-cont)
SET(COMPONENT-PTR)
FLENGTH(COMPONENT-DATA-LENGTH)
END-EXEC
* Point the component structure at the first instance of the data
SET ADDRESS OF DFHWS-component TO COMPONENT-PTR
* Store the length of a single component
MOVE LENGTH OF DFHWS-component TO COMPONENT-LENGTH
* process each instance of component data in turn
PERFORM WITH TEST AFTER
UNTIL COMPONENT-COUNT = component-num
* display the current instance of the data
DISPLAY 'component value is: ' component
* address the next instance of the component data
SET ADDRESS OF BIG-ARRAY TO ADDRESS OF DFHWS-component
SET ADDRESS OF DFHWS-component
TO ADDRESS OF BIG-ARRAY (COMPONENT-LENGTH + 1:1)
ADD 1 TO COMPONENT-COUNT
* end the loop
END-PERFORM.
* Point the component structure back at the first instance of
* of the data, for any further processing we may want to perform
SET ADDRESS OF DFHWS-component TO COMPONENT-PTR
* return to CICS.
EXEC CICS
RETURN
END-EXEC
GOBACK.
The
code above provides a generic solution to handling variably repeating
content. The array, BIG-ARRAY
, moves to the start
of each component in turn and does not remain fixed at the start of
the data. The component data structure is then moved to point at the
first byte of the next component. COMPONENT-PTR
can
be used to recover the start position of the component data if required.Here
is an example SOAP message that conforms to the WSDL document:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<applicationData xmlns="http://www.example.org/variablyRepeatingData/">
<component xmlns="">VALUE1</component>
<component xmlns="">VALUE2</component>
<component xmlns="">VALUE3</component>
</applicationData>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Here is the output produced
by the COBOL program when it processes the SOAP message:
CPIH 20080115103151 component value is: VALUE1
CPIH 20080115103151 component value is: VALUE2
CPIH 20080115103151 component value is: VALUE3