 | Level: Introductory Nik Kesic (nikk@us.ibm.com), Software Engineer, IBM
11 Aug 2005 The IBM® UniData® and UniVerse® databases (U2) offer many APIs that can leverage your application investment from a closed environment to a fully integrated open environment (Internet). This article explores some of the U2 Extended BASIC APIs, namely SOAP, DOM, XPath, XMLDB, XMAP, and the XML DB mapping tool.
Introduction
In the past, the U2 databases allowed extended development with callBASIC/callc for UniData or GCI for UniVerse. Developing C applications for communication processes tended to be a specialized task, prone to error, and time consuming. To speed up the development of communication applications over TCP/IP, U2 engineers first implemented the BASIC Socket API. This allowed the developer to create client/server applications in the U2 database structure without resorting to the complexity of the C language. The natural extension to the SOCKET API was the CallHTTP API. This allowed the developer to create higher level applications communicating with Web servers over TCP/IP. As XML (a data format for structured document interchange between disparate systems) was steadily gaining popularity, the SOAP API was implemented to extend the CallHTTP API. This enabled the developer to very easily encapsulate an XML document with SOAP.
Task summary
Upon completing the four steps below, you will be able to populate a U2 database based on a ZIP code value. Example 1 performs a SOAP connection and submits a ZIP code to the public WSDL site, which returns a SOAP response containing connection status, connection headers, and an XML document. Example 2 expands the versatility of the APIs by using the XMLDOM API to extract the XML from the SOAP document and displays the contents. Example 3 prepares U2 to analyze an XML document and map the elements to a U2 table. Example 4 uses the U2 XMAP APIs to extract elements from the XMLDOM structure and populate the ZIPCODES U2 file.
Example 1: Using SOAP in a U2 environment
Compile and run the example below (UniData requires the -I compile flag). Name the program ZIPREQ1.
Listing 1. ZIPREQ1
********************************************************************
* PROGRAM ZIPREQ1
*
* For UniData use the following include.
* $INCLUDE INCLUDE XML.H
*
* For UniVerse use the following include.
$INCLUDE UNIVERSE.INCLUDE XML.H
*
* Example of Sending a SOAP request from BASIC
*
* ZIPREQ1 - PROGRAM TO RETRIEVE A ZIP CODE -
* using SOAP API (UniData 6.1.3-Umode, Universe 10.1.6-Ideal)
* created by Nik Kesic, IBM U2 ATS, Dec 2, 2004
* Sample program only, not intended for commercial use
*
* Turn on logging
*
* RESULT=protocolLogging("ZIPCODE.log","ON",10)
* CRT "Logging started = ":RESULT
*
****
*
* You may be required to connect via a Proxy. If so insure you
* uncomment the lines below. If you are unsure that you need a
* proxy, verify you web browser proxy settings.
* Tools>Internet Options…>Connections>Lan Settings…>Proxy server
* and populate the variables below:
*
*Ret = setHTTPDefault("PROXY_NAME", "Name or IP")
*IF Ret <> 0 THEN
* STOP "Error in setHTTPDefault PROXY_NAME: " : Ret
*END
*Ret = setHTTPDefault("PROXY_PORT", "port number")
*IF Ret <> 0 THEN
* STOP "Error in setHTTPDefault PROXY_PORT: " : Ret
*END
****
PROMPT ""
CRT
DISPLAY "U2 SOAP/XML DOM/XMAP EXAMPLE"
CRT
Xfile=""
xmlString=""
XMLMap="&XML&/ZIPCODES.map"
*
* For UniData use
* XMLMap="_XML_/ZIPCODES.map"
*
PRINT "Enter Zipcode : ":
INPUT ZIPCODE
*
ZIPX = ""
ZIPX :='<?xml version="1.0" encoding="UTF-8"?>'
ZIPX :='<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">'
ZIPX :=" <soap:Body>"
ZIPX :='<GetInfoByZIP xmlns="http://www.webserviceX.NET">'
ZIPX :="<USZip>":ZIPCODE:"</USZip>"
ZIPX :=" </GetInfoByZIP>"
ZIPX :=" </soap:Body>"
ZIPX :="</soap:Envelope>"
*
URL = "http://www.webservicex.net/uszip.asmx?WSDL"
SoapAction = "http://www.webserviceX.NET/GetInfoByZIP"
Timeout = 30000
* Create the Request
Ret = SoapCreateRequest(URL , SoapAction , SoapReq)
IF Ret <> 0 THEN
STOP "Error in SoapCreateRequest: " : Ret
END
* Submit the Request
SETREQUEST.STATUS = soapSetRequestContent(SoapReq, ZIPX,1)
* PRINT "Request Content Status = ":SETREQUEST.STATUS
Ret = SoapSubmitRequest(SoapReq, Timeout, RespHeaders, RespData, SoapStatus)
IF Ret <> 0 THEN
CRT "Error in SoapSubmitRequest: " : Ret
STATUS=getSocketErrorMessage(Ret, errMsg)
CRT errMsg
STOP
END
*
PRINT "Response status : " : SoapStatus
* PRINT "Response headers: " : RespHeaders
* PRINT "Response data : " : RespData
*
*********************************************************
|
 |
Note:
Protocol logging was intentionally commented out, but experiment with this flag turned on and view the log file created. If uncommented, the protocolLogging function will create a log file in the current database account:
* RESULT=protocolLogging("ZIPCODE.log","ON",10)
* CRT "Logging started = ":RESULT
|
|
Uncomment the last PRINT statement (RespData) in the program to view the actual SOAP document returned:
* PRINT "Response data : " : RespData |
If your connection is successful, you should see the following:
Enter Zipcode : 80014
Response status : 200²OK |
The RespHeaders variable contains the response SOAP headers, which may be useful:
Enter Zipcode : 80014
* PRINT "Response headers: " : RespHeaders |
Example 2: Using DOM in a U2 environment
Continuing from Example 1, this section expands the versatility of the APIs by using the XML DOM API to extract the XML document from the received SOAP response. The strength of the XML family of BASIC APIs is the ease the BASIC programmer has extracting XML document elements.
Defining Code Functions
This example will use the following BASIC functions:
XDOMOpen – This function loads an XML document and builds a DOM tree in memory.
XDOMLocate – This function locates the starting point of the specified node string in the DOM tree and creates a locate handle.
XDOMLocateNode – This function locates the first child in the locate node handle.
XDOMWrite – This function writes the DOM structure to a string or a file.
Prerequisites:
- All the requirements from Example 1
Compile and run the example below (UniData requires the –I compile flag). Attach the code below to the end of ZIPREQ1 and rename the program ZIPREQ2.
Listing 2. ZIPREQ2
********************************************************************
* Now open the SOAP response as a DOM
*
* Make sure xml string has a line feed at the end
*
RespData=RespData:CHAR(10)
*
* Parse XML document and build DOM structure in memory
Status = XDOMOpen(RespData, XML.FROM.STRING, DOMH)
If Status <> XML.SUCCESS Then
* We hit an error
Print 'Error with XDOMOpen().'
* Gosub PrintError
Stop
End
** Position at a specific node
Status = XDOMLocate(DOMH,'//NewDataSet','',domHandle)
If Status <> XML.SUCCESS Then
* We hit an error
Print 'Error from XDOMLocate().'
* Gosub PrintError
Stop
End
Status = XDOMLocateNode(domHandle, XDOM.CHILD, XDOM.FIRST.CHILD,
XDOM.ELEMENT.NODE, sibHandle)
Status = XDOMWrite(domHandle, xmlString, XML.TO.STRING)
*
*
Print xmlString
END
*
********************************************************************
|
If your connection is successful, you should see the following:
Enter Zipcode : 80014
Response status : 200²OK
<Table><CITY>Aurora</CITY><STATE>CO</STATE><ZIP>80014</ZIP>
<AREA_CODE>303</AREA_CODE>
<TIME_ZONE>M</TIME_ZONE></Table> |
Example 3: Preparing the U2 environment
This example prepares U2 to analyze an XML document and map the elements to a U2 Table. The XMLDB Mapping Tool creates relationships between XML elements and U2 dictionary attributes. The Web site used in this example does not supply an XSD XML schema. For true integration and simplicity beyond this paper, it is important to always obtain an XML schema of the XML data you want to receive, so that the mapping of element/attributes is painless.
The mapping example below guides you through the steps of creating a schema, changing the ROOT node name to NewDataSet and the child node to Table, and a U2 database map file using the XMLDB tool. The change made to the XSD file insures compliance with the XML received from the Web site.
Prerequisites:
- All the requirements from Examples 1 and 2
- Installation of the XMLDB Mapping Tool from the U2 Clients CD
Create a file and dictionary called ZIPCODES. Populate the ZIPCODES dictionary to reflect the following.
Listing 3. ZIPCODES Dictionary
Type
Field......... Field. Field........ Conversion.. Column......... Output Depth
Name.......... Number Definition... Code........ Heading........ Format Assoc..
@ID D 0 ZIPCODES 10L S
ZIP D 0 Zip Code 10R S
CITY D 1 City 20L S
STATE D 2 State 15L S
AREA_CODE D 3 Area Code 4R S
TIME_ZONE D 4 Time Zone 3L S
|
Perform the following from TCL:
From UniVerse:
>LIST ZIPCODES ZIP CITY STATE AREA_CODE TIME_ZONE TOXML ELEMENTS
WITHSCHEMA TO "ZIPCODES" |
From UniData:
:LIST ZIPCODES ZIP CITY STATE AREA_CODE TIME_ZONE TOXML ELEMENTS
WITHSCHEMA TO ZIPCODES |
Either database command creates two files (ZIPCODES.xml and ZIPCODES.xsd) in the _XML_ (UniData) or &XML& (UniVerse) directory, as shown below:
Listing 4. ZIPCODES.xml
<?xml version="1.0"?>
<ROOT
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ZIPCODES.xsd">
</ROOT> |
Listing 5. ZIPCODES.xsd
<?xml version="1.0"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:annotation>
<xsd:documentation xml:lang="en">
account: C:\IBM\ud71\Demo
command: LIST ZIPCODES ZIP CITY STATE AREA_CODE TIME_ZONE TOXML
WITHSCHEMA TO ZIPCODES
</xsd:documentation>
</xsd:annotation>
<xsd:element name="NewDataset">
<xsd:complexType>
<xsd:sequence maxOccurs='unbounded'>
<xsd:element name="Table" maxOccurs="unbounded">
<xsd:complexType>
<xsd:attribute name="_ID" type="xsd:string"/>
<xsd:attribute name="ZIP" type="xsd:string"/>
<xsd:attribute name="CITY" type="xsd:string"/>
<xsd:attribute name="STATE" type="xsd:string"/>
<xsd:attribute name="AREA_CODE" type="xsd:string"/>
<xsd:attribute name="TIME_ZONE" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema> |
Because the public Web site does not supply an XSD XML schema file, the step below is necessary. The ROOT element node is not ROOT, but rather NewDataSet, and the child node is Table. The above XSD file was manually edited to reflect this.
Visit WebserviceX.net (see Resources), select the GetInfoByZip operation, and enter a US Zip code. The returned XML will display Table as the key node for returned data elements:
Listing 6. ZIPCODES.xml
<?xml version="1.0" encoding="utf-8"?>
<NewDataSet>
<Table>
<CITY>Aurora</CITY>
<STATE>CO</STATE>
<ZIP>80013</ZIP>
<AREA_CODE>303</AREA_CODE>
<TIME_ZONE>M</TIME_ZONE>
</Table>
</NewDataSet> |
Using the XMLDB tool, create an XMLDB XMAP file (ZIPCODES.map) using the ZIPCODES.xsd file and the U2 table ZIPCODES.
Figure 1. Add new Xmap file
Select the parent account (Demo) and Map name of (ZIPCODES).
Figure 2. New RDB XML map file
Specify U2 file (ZIPCODES).
Figure 3. Source U2 files
Specify the schema file (ZIPCODES.xsd).
Figure 4. DTD or XSD file
Select the ROOT element.
Figure 5. Root element
The XML/DB Tools will now display.
Figure 6. ZIPCODES.map display
Create relationships (mapping) between the ZIPCODES dictionary and schema.
Figure 7. Table schema mapping
Your ZIPCODES.map file must look like the following when completed (click on the Source tab):
Figure 8. The ZIPCODES.map file
Example 4: Using XMAP in a U2 environment
This example concludes the “U2 SOAP API client parts 1, 2, and 3” examples. The U2 XMAP API is used to extract elements from the XDOM created string "xmlstring". This string is manipulated using XMAP functions to populate the ZIPCODES U2 file. Notice how the BASIC code below simplifies extracting data from XML element names using the XMAPReadNext function with information from the map file.
Defining Code Functions
This example will use the following BASIC functions:
XMAPopen – This function opens an XML document as a U2XMAP data set.
XMAPReadNext – This function retrieves the next record from the U2XMAP dataset and formats it as a record of the UniVerse file that is being mapped.
XMAPClose – This function closes the U2XMAP dataset handle and frees all related structures and memory.
XDOMClose – This function frees the DOM structure.
Prerequisites:
- All the requirements of examples 1, 2, and 3
Compile and run the example below (UniData requires the –I compile flag). Attach the code below to the end of ZIPREQ2 and rename the program ZIPREQ3.
Listing 7. ZIPREQ3
**********************************************************
*
* Print xmlString ;* Comment out this statement when attaching the
* END ;* U2 SOCKET API part 4 BASIC code.
*
* Open XMAP dataset for reading
Status = XMAPOpen(xmlString, XML.FROM.STRING, XMLMap, XML.FROM.FILE, Xfile)
* PRINT Status
If Status <> XML.SUCCESS Then
* We hit an error
Print 'Error with XMAPOpen().'
Gosub PrintError
Stop
End
Open 'ZIPCODES' to F1 Else Stop 'Error opening file ZIPCODES.'
* Read records from XMAP dataset, write to ZIPCODES file
Record = ''
Loop
Status = XMAPReadNext(Xfile, 'ZIPCODES', Record)
Until Status = XML.EOF Do
If Status <> XML.SUCCESS Then
Print 'XMAPReadNext() error.'
Gosub PrintError
Stop
End
ID = Record<1>
Rec = FIELD(Record, @FM, 2, 999)
Write Rec to F1, ID ON ERROR STOP 'Write to file ZIPCODES failed.'
Print 'ID ':ID:' written to the ZIPCODES file.'
Repeat
If Status = XML.EOF Then
Print 'EOF reached in document.'
End
* Close all handles before exiting
Status = XMAPClose(Xfile)
If Status <> XML.SUCCESS Then
* We hit an error
Gosub PrintError
Stop
End
Status = XDOMClose(domHandle)
If Status <> XML.SUCCESS Then
* We hit an error
Print 'Error with XDOMClose().'
Gosub PrintError
Stop
End
Status = XDOMClose(DOMH)
If Status <> XML.SUCCESS Then
* We hit an error
Print 'Error with XDOMClose().'
Gosub PrintError
Stop
End
Close F1
Stop
*
* RESULT=protocolLogging("ZIPCODE.log","OFF",10)
* CRT "Logging started = ":RESULT
*
PrintError:
* Using XMLGetError() we can find out the very last error code and
* its corresponding message. This allows us to display a descriptive
* reason for the problem.
Tmp = XMLGetError(Code,Msg)
Print
Print 'The error description and code:'
Print '------------------------------------------'
Print 'Error desc:' ; Print Msg
Print 'Error code: ':Code
Print '------------------------------------------'
Return
End |
If your connection is successful, you should see the following:
Enter Zipcode : 80013
Response status : 200²OK
ID 80013 written to the ZIPCODES file.
EOF reached in document. |
Perform the following command from TCL:
:CT ZIPCODES 80013
ZIPCODES:
80013:
Aurora
CO
303
M |
Conclusion
After completing the examples above, you should have a SOAP client application in U2 that can access a Zip code Web service of a remote non-U2 enabled system. The XML document received is then used to populate a U2 table. There are many functions in the Extended BASIC APIs which were not discussed that can extend the power of the application developer even more. U2 engineering continues to extend BASIC with what started out as the SOCKET API to other disciplines, making it easier for the application developer to create complex applications without the need to create complex, time consuming code.
Resources - Visit WebserviceX.net, as outlined in Example 3, to get Table as the key node for returned data elements
- Learn more about U2 by visiting the IBM U2 Web site.
- For UniData, the UniBasic Extensions, Version 6.1 manual describes the following extensions to UniBasic: UniBasic Socket API, Using CallHTTP, Using SSL with CallHTTP and the Socket Interface, and Using WebSphere MQ with UniData.
- For UniVerse, the BASIC Extensions V 10.1 (G251-1908-00) manual describes the following extensions to UniVerse BASIC: UniVerse BASIC Socket API, Using CallHTTP, Using SSL with CallHTTP and the Socket Interface, and Using WebSphere MQ with UniVerse.
- "Zeroing in on UniData problems" (developerWorks, September 2004) assists with the problem determination process for someone administering or supporting UniData databases.
- Read "ASP.NET Web Development using RedBack objects" (developerWorks, June 2005) to learn how to use ASP.NET with RedBack® objects to access your UniData or UniVerse database from the Web in a simple way, with examples in VB and C#.
- Visit the developerWorks DB2 zone to learn more about DB2. You'll find technical documentation, how-to articles, education, downloads, product information, and more.
- Visit the developerWorks blogs to get involved in the developerWorks community.
About the author  | 
|  | Nik Kesic works for the IBM U2 Advanced Technical Support group in Denver Colorado. Nik provides consultancy, level 3 support, and training and has published articles on Web enablement using RedBack, Sockets, XML, SOAP, SSL, and Encryption.
|
Rate this page
|  |