Batch modernization in z/OS by the example The Batch modernization made simple. Batch modernization in z/OS by the example : The Batch modernization made simple. Table of Contents By the same author ............................................................................................................. v Preface: The Batch modernization move ................................................................................ vi 1. Cobol and Java ............................................................................................................... 1 1. TstHello example 1 .................................................................................................. 2 1.1. Create the Cobol program TSTHELLO ............................................................. 3 1.2. Create the Jcl JCOBOL and submit it ............................................................... 4 1.3. In the USS generate HelloJ class ..................................................................... 7 1.4. In the TSO/E environment execute TSOHELLO module and review your outputs ................................................................................................................... 8 1.5. Possible causes of errors ................................................................................ 9 2. TstHello example 2 ................................................................................................ 10 2.1. Copy the Cobol program to /a/userid location in the USS. ................................... 11 2.2. Create the TstHello.bat script file ................................................................... 12 2.3. Execute TstHello.bat .................................................................................... 14 2.4. Possible causes of errors. .............................................................................. 15 3. TstHello example 3 ................................................................................................ 16 3.1. Create the TstHelloJ.java program in /a/userid/myjava ........................................ 17 3.2. Create a modified TstHello.cbl program in sub-directory ooHello ......................... 18 3.3. Create the TstooHello.bat script ..................................................................... 20 3.4. Execute the script ........................................................................................ 22 3.5. The generated TstooHello.java source ............................................................. 23 3.6. Possible causes of errors. .............................................................................. 24 4. The oosample example ........................................................................................... 25 4.1. The structure of the application ...................................................................... 26 4.2. The Cobol main program TestAccounts.cbl ...................................................... 27 4.3. The Cobol program Account.cbl .................................................................... 29 4.4. The Cobol program CheckingAccount.cbl ........................................................ 32 4.5. The Check java program ............................................................................... 35 4.6. The oosample.bat script file .......................................................................... 36 4.7. Execute the script ........................................................................................ 38 2. Cobol, XML and XSD .................................................................................................... 39 1. The XMLCOB1 example ........................................................................................ 40 1.1. The Cobol program ..................................................................................... 41 1.2. The XSD processing .................................................................................... 66 1.3. The build of the module and its execution ....................................................... 69 2. The XMLQRY1 example ........................................................................................ 72 2.1. The Cobol program ..................................................................................... 73 2.2. The build of the module and its execution ....................................................... 90 3. C++ and XML .............................................................................................................. 91 1. Try the pre-installed IBM samples programs ............................................................... 92 2. Generate and execute the samples in the USS ............................................................. 94 2.1. Get and install the GNU gmake utility ............................................................ 95 2.2. Prepare your environment ............................................................................. 96 2.3. Configure and execute gmake ........................................................................ 97 2.4. Script the build of the examples ..................................................................... 98 2.5. Script the execution of the examples ............................................................... 99 3. Generate in the USS to a Z/OS load library and execute in Z/OS ................................... 104 3.1. Install gmake ............................................................................................ 105 3.2. Prepare your environment ........................................................................... 106 3.3. Prepare the Configure script ........................................................................ 107 3.4. Prepare a gmake script ............................................................................... 108 iii Batch modernization in z/OS by the example 3.5. Execute the scripts and loadmodules in a Z/OS batch job .................................. 4. Fully generate an example in Z/OS ......................................................................... 5. How to use the z/OS specific parser classes .............................................................. 5.1. Generate zsamples ..................................................................................... 5.2. Execute zsamples in the USS ....................................................................... 5.3. Generate zsamples in Z/OS ......................................................................... 5.4. Execute zsamples in Z/OS ........................................................................... 6. How to use the XSLT Processor, C++ Edition ........................................................... 6.1. Generate the xslt examples in the USS .......................................................... 6.2. Execute the xslt examples in the USS ............................................................ 6.3. Generate the xslt examples to Z/OS .............................................................. 6.4. Execute the xslt examples in Z/OS ............................................................... 6.5. Fully generate a xslt example in Z/OS ........................................................... 6.6. Execute the Xalan transformer directly .......................................................... 6.7. Execute the test XSLT utility ....................................................................... 7. How to call the XML Toolkit from a Cobol program .................................................. 7.1. Set up the test files for the SPFEXML application ........................................... 7.2. The SPFEXML cobol program ..................................................................... 7.3. The A1CCDLGT program ........................................................................... 7.4. The SAXPRSE program ............................................................................. 7.5. The SAXHNDL program ............................................................................ 7.6. The SAXPRSEH include ............................................................................ 7.7. The SAXHNDLH include ........................................................................... 7.8. The JCL ................................................................................................... 7.9. The outputs produced by the SPFEXML application ........................................ 4. Conclusion .................................................................................................................. iv 109 115 120 121 122 125 126 127 128 129 131 132 133 138 140 142 143 144 147 149 153 155 157 159 163 164 By the same author • Batch modernization in z/OS by the example as a web document: http://patrice.cotte.free.fr/techpages/bmv1/index.html • MyDocbook or how turn your Eclipse IDE into a publishing environment: http://patrice.cotte.free.fr/ techpages/mydocbook/index.html For an easier reading the author recommends to browse the web formatted versions of these books. v Preface: The Batch modernization move The 'Batch modernization on z/OS' is IBM's response to make the Mainframe world more in phase with the distributed world, which includes the use of XML and inter-operability between languages, cross-platform generation and execution. IBM has published a number of manuals on the subject. • Redbook Batch Modernization on z/OS, SG24-7779-01, July 2012 • Redbook New Ways of Running IBM z/OS Batch Applications, SG24-8116-00,n May 2013 • Redbook New Ways of Running IBM z/OS Batch Applications, Volume 1 CICS Transaction Server, SG24-7991-00, October 2013 • Redbook New Ways of Running IBM z/OS Batch Applications, Volume 4 IBM IMS, SG24-8119-00, May 2014 To this day there is no Volume 2 and no Volume 3. These manuals come in addition to • The Enterprise COBOL for z/OS V4.2 Programming Guide, SC23-8529-01, 2001-2009 • The XML Processing on z/OS,SG24-7810-00, December 2009 • XML Toolkit for z/OS User's guide All these publications contain many examples of the new ways to execute applications in a z/OS system. While these examples focus on the coding the generation and setup of the examples is often confusing and not enough documented. This is where this books comes in. This manual very simply explains how to implement a number of these examples: • Chapter 1 - Cobol and Java • Generate and execute the Cobol and Java TstHello application in various ways. • Generate and execute the Cobol and Java oosample application in the USS. • Chapter 2 - Cobol, XML and XSD • Generate and execute the Cobol XMLCOB1 program. • Generate and execute the Cobol XMLQRY1 program. • Chapter 3 - The XML Parser, C++ Edition • Generate the xslt examples in the USS. • Execute the xslt examples in the USS. • Generate the xslt examples to z/OS. • Execute the xslt examples in Z/OS. vi Preface: The Batch modernization move • Fully generate an xslt example in Z/OS. • Execute the Xalan transformer directly. • Execute the test XSLT utility. • Call the XML Toolkit from a Cobol program. vii Chapter 1. Cobol and Java This chapter gathers a number of examples that demonstrate how Cobol and Java can interoperate. • TstHello example 1: Cobol program TSTHELLO is generated and run in TSO/E, calls Java class HelloJ in the USS • TstHello example 2: Cobol program TSTHELLO and Java class HelloJ are generated and run in the USS • TstHello example 3: Java program TstHelloJ calls OO Cobol TSTHELLO that calls Java class HelloJ, in the USS 1 Cobol and Java 1. TstHello example 1 Reference Enterprise Cobol Programming Guide V4R2, chapter 16, Compiling, linking and running OO applications. Requirements • User has access to the TSO/E environment and the IBM Cobol compiler at level V4 or higher • User has access to the USS 2 Cobol and Java 1.1. Create the Cobol program TSTHELLO This source will be stored as a member of a library in the TSO/E environment. cbl thread,dll IDENTIFICATION DIVISION. Program-id. "TSTHELLO" recursive. * ---------------------------------------------------------* This example has been copied from the Enterprise Cobol * Programming guide V4R2, chapter 16, Compiling, linking and * running OO applications. * ---------------------------------------------------------Environment division. Configuration section. Repository. Class HelloJ is "HelloJ". Data division. Procedure division. Display "COBOL program TSTHELLO entered." * ** Java is invoked, not called! Invoke HelloJ "sayHello" Display "COBOL program TSTHELLO returned from Java." Goback . End program "TSTHELLO". Note the following • Cbl options thread,dll • HelloJ java program is define as a class in the Repository section (OO Cobol) • HelloJ is invoked , not called 3 Cobol and Java 1.2. Create the Jcl JCOBOL and submit it This Jcl will be stored as a member of a library in the TSO/E environment. //USERIDC JOB accnt,'ENTERPRISE COBOL',CLASS=A, //* TYPRUN=SCAN, //* RESTART=GO, // MSGCLASS=X, //JCOBOL PROC COBOLHQ='', // SRCFILE='', // JVMBR='', // MEMBER='', // CPARM='', // LPARM='', // LOADLIB='' //* //COB2 EXEC PGM=IGYCRCTL,REGION=512K, // PARM=&CPARM //STEPLIB DD DISP=SHR,DSN=&COBOLHQ..SIGYCOMP //SYSLIB DD DISP=SHR,DSN=&COBOLHQ..SIGYMAC // DD DISP=SHR,DSN=CEE.SCEESAMP //SYSLIN DD DSN=&&LOADSET,DISP=(,PASS),UNIT=VIO, // SPACE=(TRK,(5,2)), // DCB=(RECFM=FB,LRECL=80,BLKSIZE=2960) //SYSPRINT DD SYSOUT=*,DCB=(LRECL=121,BLKSIZE=3630,RECFM=FBA) //SYSMDECK DD SYSOUT=* //SYSPUNCH DD DUMMY //* --------------------- SYSJAVA ALLOCATION IS FOR OO COBOL //SYSJAVA DD PATH='/a/userid/myjava/&JVMBR..java', // PATHOPTS=(OWRONLY,OCREAT,OTRUNC), // PATHDISP=KEEP, // PATHMODE=SIRWXU, // FILEDATA=TEXT //* --------------------------------------------------------//SYSTERM DD UNIT=VIO,SPACE=(TRK,(5,2)) //SYSUT1 DD UNIT=VIO,SPACE=(CYL,(2,1)) //SYSUT2 DD UNIT=VIO,SPACE=(CYL,(2,1)) //SYSUT3 DD UNIT=VIO,SPACE=(CYL,(2,1)) //SYSUT4 DD UNIT=VIO,SPACE=(CYL,(1,1)) //SYSUT5 DD UNIT=VIO,SPACE=(CYL,(1,1)) //SYSUT6 DD UNIT=VIO,SPACE=(CYL,(1,1)) //SYSUT7 DD UNIT=VIO,SPACE=(CYL,(1,1)) //* ----------------------------------------------- SYSIN //SYSIN DD DISP=SHR,DSN=&SRCFILE(&MEMBER) //* //******************************************************************130* //* LINK THE GENERATED PROGRAM * //********************************************************************** //* //LKED EXEC PGM=HEWL,REGION=512K, // PARM=&LPARM //SYSLIB DD DISP=SHR,DSN=CEE.SCEELKED 4 Cobol and Java // DD DISP=SHR,DSN=CEE.SCEELKEX // DD DISP=SHR,DSN=CEE.SCEELIB << IGZCJAVA // DD DISP=SHR,DSN=&COBOLHQ..SIGYCOMP //SYSLIN DD DSN=&&LOADSET,DISP=(OLD,DELETE) //SYSPRINT DD SYSOUT=*,DCB=(LRECL=121,BLKSIZE=3630,RECFM=FBA) //SYSUT1 DD UNIT=VIO,SPACE=(TRK,(5,2)) //* ----------------------------------------- SYSLMOD //SYSLMOD DD DISP=SHR,DSN=&LOADLIB(&MEMBER) //* // PEND //********************************************************************** //* COMPILE and LINK program * //********************************************************************** //COMPLINK EXEC JCOBOL, // JVMBR='HelloJ', // MEMBER='TSTHELLO', // SRCFILE='userid.COBOL.SRC', // COBOLHQ='Z/OSSYS.COBOL.V4R2M0.PDO0939', // LOADLIB='userid.COBOL.DLLLIB', // CPARM='(SOURCE,XREF,LIST,LIB,APOST,NOSEQ,RENT,MDECK)', // LPARM='(XREF,LIST,RENT,LET,DYNAM(DLL),CASE(MIXED))' //LKED.SYSLIN DD DSN=&&LOADSET,DISP=(OLD,DELETE) // DD * INCLUDE '/usr/lpp/java/J7.1/bin/j9vm/libjvm.x' * INCLUDE '/usr/lpp/cobol/lib/igzcjava.x' * INCLUDE IGZCJAVA IMPORT CODE,'IGZCJAVA','GetClassObject' IMPORT CODE,'IGZCJAVA','GetEnvPtr' IMPORT CODE,'IGZCJAVA','GetInstanceData' IMPORT CODE,'IGZCJAVA','GetJVMPtr' /* //********************************************************************** //* RUN program * //********************************************************************** //GO EXEC PGM=TSTHELLO,COND=((4,LT,COMPLINK.COB2), // (4,LT,COMPLINK.LKED)), // PARM='/ENVAR("_CEE_ENVFILE=/a/userid/myjava/ENV") // POSIX(ON),XPLINK(ON)' //STEPLIB DD DISP=SHR,DSN=userid.COBOL.DLLLIB //SYSOUT DD SYSOUT=* //SYSPRINT DD SYSOUT=* //JAVAIN DD DUMMY //JAVAOUT DD PATH='/a/userid/myjava/thjavaout', // PATHOPTS=(OWRONLY,OCREAT,OTRUNC), // PATHMODE=(SIRUSR,SIWUSR,SIRGRP) //JAVAERR DD PATH='/a/userid/myjava/thjavaerr', // PATHOPTS=(OWRONLY,OCREAT,OTRUNC), // PATHMODE=(SIRUSR,SIWUSR,SIRGRP) // Note the following 5 Cobol and Java • This job (re)creates HelloJ.java empty in SYSJAVA location the USS • If igzcjava.x does not exist a copy exists as IGZCJAVA in the CEE.SCEELIB library • The igzcjava.x file only contains a list of IMPORTs. Aternatively you can add them to the SYSLIN • This job creates a DLL, which means the output library SYSLMOD must be a PDSE Because class HelloJ will be (re)created empty you should submit your JCL leaving out the GO step. Once your HelloJ class is ready use again that JCL to submit the GO step only. 6 Cobol and Java 1.3. In the USS generate HelloJ class • Edit /a/userid/HelloJ.java and add these lines class HelloJ { public static void sayHello() { System.out.println("Hello World, from Java!"); } } • Compile HelloJ.java into HelloJ.class javac HelloJ.java • Create /a/userid/myjava/ENV environment file with this contents PATH=/bin:/usr/lpp/java/J7.1/bin LIBPATH=/lib:/usr/lib:/usr/lpp/java/J7.1/bin:/usr/lpp/java/J7.1/bin/j9vm CLASSPATH=/a/userid/myjava:/usr/lpp/java/J7.1/bin/j9vm 7 Cobol and Java 1.4. In the TSO/E environment execute TSOHELLO module and review your outputs Edit the JCOBOL jcl and use the RESTART parameter in the job card to execute the GO step only //GO EXEC PGM=TSTHELLO,COND=((4,LT,COMPLINK.COB2), // (4,LT,COMPLINK.LKED)), // PARM='/ENVAR("_CEE_ENVFILE=/a/userid/myjava/ENV") // POSIX(ON),XPLINK(ON)' //STEPLIB DD DISP=SHR,DSN=userid.COBOL.DLLLIB //SYSOUT DD SYSOUT=* //SYSPRINT DD SYSOUT=* //JAVAIN DD DUMMY //JAVAOUT DD PATH='/a/userid/myjava/thjavaout', // PATHOPTS=(OWRONLY,OCREAT,OTRUNC), // PATHMODE=(SIRUSR,SIWUSR,SIRGRP) //JAVAERR DD PATH='/a/userid/myjava/thjavaerr', // PATHOPTS=(OWRONLY,OCREAT,OTRUNC), // PATHMODE=(SIRUSR,SIWUSR,SIRGRP) // The job executes with a Return code 0. The SYSOUT shows COBOL program TSTHELLO entered. COBOL program TSTHELLO returned from Java. In the USS the /a/userid/myjava/thjavaout output shows Hello World, from Java! 8 Cobol and Java 1.5. Possible causes of errors At link time, unresolved references. • In the USS, navigate to the Java location and make sure libjvm.x exists • In the USS, navigate to the cobol location and make sure igzcjava.x exists. You can work around this issue by adding the IMPORTS as shown above. At execution time the job abends with a S0C1 abend code, a CEE3501S LE code and message 'libjvm.so not found'. Check out the ENV file is configured as above At execution time the job issues a 'main thread Exception' with a message stating the application is not XPLINK compatible. Make sure the GO step specifies XPLINK(ON) 9 Cobol and Java 2. TstHello example 2 Although not explained in the Programming Guide, Chapter 16, Section "Compiling, linking and running OO applications under z/OS UNIX" it is possible to generate and execute the Cobol program entirely in the USS. This information has been made available by Robert Sample on October 14, 2010 in the IBM Mainframe forum. Requirements • The IBM Cobol compiler at level V4 or higher • User has access to the USS • The cobol product has been installed in the USS, the usual location is usr/lpp/cobol 10 Cobol and Java 2.1. Copy the Cobol program to /a/userid location in the USS. cbl thread,dll IDENTIFICATION DIVISION. Program-id. "TSTHELLO" recursive. * ---------------------------------------------------------* This example has been copied from the Enterprise Cobol * Programming guide V4R2, chapter 16, Compiling, linking and * running OO applications. * ---------------------------------------------------------Environment division. Configuration section. Repository. Class HelloJ is "HelloJ". Data division. Procedure division. Display "COBOL program TSTHELLO entered." * ** Java is invoked, not called! Invoke HelloJ "sayHello" Display "COBOL program TSTHELLO returned from Java." Goback . End program "TSTHELLO". Note the following • The cobol program is identical to the cobol program in TSO/E • The HelloJ class does not need a rebuild if it was generated for the prior example. 11 Cobol and Java 2.2. Create the TstHello.bat script file # # This script compiles, links the TstHello cobol program and # executes the resulting library libTstHello.so # # - XPLINK(ON) run options is required. # # - Xmls and Xmx must be bigger than 1M in order to initialize # the JVM. # # - append -verbose:gc to COBJVMINIOPTIONS to get the detail # of the IBM JVM garbage collection on screen. # # - append -Xverbosegclog:name.lst to COBJVMINIOPTIONS to get the detail # of the IBM JVM garbage collection written to file name.lst # JAVASIDEDECKPATH=${JAVA_HOME}/bin/classic COBSIDEDECKPATH=/sys/cobol/V5R1M0/usr/lpp/cobol/lib COBCOPYPATH=/sys/cobol/V5R1M0/usr/lpp/cobol/include export COBJVMINITOPTIONS="-Xms1200000 -Xmx1200000 -Xverbosegclog:TstHell export _CEE_RUNOPTS="XPLINK(ON)" # # ------------------------------------------------------------------# cob2 cheatsheet: # -bdll the executable module is a DLL # -c compile no link # -Ipath names a path for the copybook search # -o name names the object module # -qopt,opt, compiler options # -v verbose, echoes the commands that cob2 generates # -# displays compile and link steps without execution # # Compile TstHello.cbl into TstHello.o + TstHello.java. # The report goes to TstHello.lst # # cob2 syntax: see the Enterprise Cobol Programming Guide chapter 15. # the cob2 report always goes to xxxx.lst output # cob2 -c -qdll,thread I${COBCOPYPATH} TstHello.cbl # # Link TstHello.o into dll libTstHello.so # The report goes to TstHellolnk.lst # cob2 -V -bdll,map,list -o libTstHello.so TstHello.o ${JAVASIDEDECKPATH}/libjvm.x ${COBSIDEDECKPATH}/igzcjava.x>TstHellolnk.lst # # Execute libTstHello.so # ./libTstHello.so 12 Cobol and Java Note the following • The cob2 -V command has been split over three lines for an easier reading. It must actually be a single line. • The 'so' file name must be the prefix 'lib' with the name of the program concatenated. 13 Cobol and Java 2.3. Execute TstHello.bat The execution of the script produces a number of lines similar as the below ones. PP 5655-S71 IBM Enterprise COBOL for z/OS 4.2.0 in progress ... End of compilation 1, program TSTHELLO, no statements flagged. IGD01008I ALLOCATION SET TO SCTEMPD M0610 IGD01010I ALLOCATION SET TO SGTEMPD STORAGE GROUP IGD01008I ALLOCATION SET TO SCTEMPD M0610 IGD01010I ALLOCATION SET TO SGTEMPD STORAGE GROUP IEW2617I 4C43 DEFINITION SIDE FILE IS EMPTY. THERE ARE NO SYMBOLS TO BE EXPORTED. COBOL program TSTHELLO entered. Hello World, from Java! COBOL program TSTHELLO returned from Java. USERID:/a/userid/myjava: > 14 Cobol and Java 2.4. Possible causes of errors. Command cob2 not found. • Check out the cobol product is installed. • Check out the path (for example in .profile) contains the location of the cob2 executable. Unresolved references at link time. • Check out the PATH variables are correct. • Check out libjvm.x and igzcjava.x exist. Errors at execution time. • JVM initialization errors, Xms or Xmx too small. Adjust these values in the COBJVMINITOPTIONS • Application noXPLINK attempts to call an XPLink class. Check out the _CEE_RUN_OPTS variable. 15 Cobol and Java 3. TstHello example 3 In this example Java program TstHelloJ calls TstooHello cobol program that invokes HelloJ as seen in the prior sections. It is assumed the current location in the USS is /a/userid/myjava Requirements • The IBM Cobol compiler at level V4 or higher • User has access to the USS • The cobol product has been installed in the USS, its usual location is usr/lpp/cobol 16 Cobol and Java 3.1. Create the TstHelloJ.java program in /a/userid/myjava /* * TstHelloJ java program is * mixed application. * * TstHelloJ java class * >> creates an instance of * Cobol TstooHello cobol * >> TstooHello calls * */ import ooHello.*; public class TstHelloJ { the top program in a Cobol and java TstooHello, a class derived from program java class HelloJ public static void main(String [] args){ int rc = 0; System.out.println("TstHelloJ main is executing!"); // Create instance of TstooHello class TstooHello tsth = new TstooHello(); System.out.println("TstHelloJ has created TstooHello object"); // Invoke method of TstooHello class tsth.CallHelloJ(); } } 17 Cobol and Java 3.2. Create a modified TstHello.cbl program in sub-directory ooHello Create ooHello folder in /a/userid/myjava location Create TstooHello.cbl program in ooHello folder cbl thread,dll,pgmname(longmixed) IDENTIFICATION DIVISION. * -----------------------------------------------------------* This example has been copied from the Enterprise Cobol * Programming guide V4R2, chapter 16, Compiling, linking and * running OO applications. * -----------------------------------------------------------Class-id. TstooHello inherits Base. Environment division. Configuration section. Repository. Class Base is "java.lang.Object" Class HelloJ is "HelloJ" Class TstooHello is "ooHello.TstooHello". * -----------------------------------------------------------* Note TstooHello appears also as a class "ooHello.TstooHello" * This determines the setup of package ooHello in the generated * java source TstooHello. * -----------------------------------------------------------* Class definition Identification division. Object. Data division. Working-storage section. Procedure division. * Define a method. Identification division. Method-id. 'CallHelloJ'. Data division. Linkage section. Procedure division. Display "COBOL program TSTOOHELLO entered." * ** Java is invoked, not called! Invoke HelloJ "sayHello" Display "COBOL program TSTOOHELLO returned from Java." Goback . End Method 'CallHelloJ'. * 18 Cobol and Java End Object. End Class TstooHello. Note the following • TstooHello.cbl is an OO (Object Oriented) program with a class, an object and a method • The repository defines class TstooHello as "ooHello.TstooHello". This instructs the cob2 compiler to create package ooHello in the corresponding TstHello.java program. • Method CallHelloJ contains Cobol displays around the invocation of the HelloJ java class 19 Cobol and Java 3.3. Create the TstooHello.bat script # # Script TstooHello.bat compiles and links the TstHelloJ class and # the TstooHello.cbl cobol program. # JAVASIDEDECKPATH=${JAVA_HOME}/bin/classic COBSIDEDECKPATH=/sys/cobol/V5R1M0/usr/lpp/cobol/lib COBCOPYPATH=/sys/cobol/V5R1M0/usr/lpp/cobol/include # # ------------------------------------------------------------------# cob2 cheatsheet: # -bdll the executable module is a DLL # -c compile no link # -Ipath names a path fot copybook search # -o name names the object module # -qopt,opt, compiler options # -v verbose, echoes the commands that cob2 generates # -# displays compile and link steps without execution # ------------------------------------------------------------------# Java and Cobol have different requirements regarding 'subroutines'. # # The Java caller can only call a Cobol through a package, which # leads to the following: # # - The cobol program defines classes using the package.name format. # >> cob2 then creates a java program with the corresponding # package name. # >> a directory with the same name as the package must exist in # the current location. # >> the resulting library must contain the package name # ('lib' + package-name + '-' + cobol-name + '.so'. # the library must reside in the package directory. # # See Link #1 below. # # - The java caller must import the cobol package. When the class # is created it is searched under its true name so we also need # a library under the Cobol program name. # # See Link #2 below. # # ------------------------------------------------------------------# Compile TstooHello.cbl into TstooHello.o + TstooHello.java. # The report goes to TstooHello.lst # # cob2 syntax: see the Enterprise Cobol Programming Guide chapter 15. # cob2 -c -bdll ./ooHello/TstooHello.cbl # # Link #1 TstooHello.o into dll libooHello_TstooHello.so # The report goes to TstooHellolnk.lst 20 Cobol and Java # cob2 -bdll,map,list,xref -o ./ooHello/libooHello_TstooHello.so TstooHello.o ${JAVASIDEDECKPATH}/libjvm.x ${COBSIDEDECKPATH}/igzcjava.x >TstooHellolnk.lst # # Link #2 TstooHello.o into dll libTstooHello.so # The report goes to TstooHellolnk.lst # cob2 -bdll,map,list,xref -o ./ooHello/libTstooHello.so TstooHello.o ${JAVASIDEDECKPATH}/libjvm.x ${COBSIDEDECKPATH}/igzcjava.x >TstooHellolnk.lst # # Move the generated class to the ooHello directory # mv TstooHello.java ooHello # # Create TstooHello class # javac ooHello/TstooHello.java # # Build TstHelloJ java class # javac TstHelloJ.java # # Execute the application # java -Djava.library.path="/a/userid/myjava/ooHello" TstHelloJ Note the following • cob2 lines appear on several lines for an easier reading. They are actually single lines commands • ooHello folder must exist in /a/userid/myjava • The cobol program is linked first in order to create the libooHello_TstooHello.so library • The cobol program is linked again in order to create the libTstooHello.so library • TstHelloJ class is finally passed to java for execution along with a Dparm 21 Cobol and Java 3.4. Execute the script The execution of the script produces a few lines similar to the below ones. USERID:/a/userid/myjava: >TstooHello.bat PP 5655-S71 IBM Enterprise COBOL for z/OS 4.2.0 in progress ... End of compilation 1, class TSTOOHELLO, no statements flagged. IGD01008I ALLOCATION SET TO SCTEMPD M0610 IGD01010I ALLOCATION SET TO SGTEMPD STORAGE GROUP IGD01008I ALLOCATION SET TO SCTEMPD M0610 IGD01010I ALLOCATION SET TO SGTEMPD STORAGE GROUP IGD01008I ALLOCATION SET TO SCTEMPD M0610 IGD01010I ALLOCATION SET TO SGTEMPD STORAGE GROUP IGD01008I ALLOCATION SET TO SCTEMPD M0610 IGD01010I ALLOCATION SET TO SGTEMPD STORAGE GROUP TstHelloJ main is executing! TstHelloJ has created TstooHello object COBOL program TSTOOHELLO entered. Hello World, from Java! COBOL program TSTOOHELLO returned from Java. USERID:/a/userid/myjava: > 22 Cobol and Java 3.5. The generated TstooHello.java source From the TstooHello.cbl program cob2 has generated the TstooHello.java source, which is then processed by the java compiler. // PP 5655-S71 IBM Enterprise COBOL for z/OS 4.2.0 // // Generated Java class definition for COBOL class ooHello.TstooHello // // Date generated: 10/31/2014 // Time generated: 10:59:53 // // ** Do not edit or modify this file! ** // ** It is (and must be) regenerated whenever the ** // ** COBOL class is compiled. ** // package ooHello; public class TstooHello extends java.lang.Object { public native void CallHelloJ(); private native static void _classInit(); static { System.loadLibrary("ooHello_TstooHello"); ooHello.TstooHello._classInit(); } } Note the following • package statement ooHello has been generated • loadLibrary name "ooHello_TstooHello" • CallHelloJ Java class execution 23 Cobol and Java 3.6. Possible causes of errors. Unresolved references at link time. • Check out the PATH variables are correct. • Check out libjvm.x and igzcjava.x exist. • Check out the consistency between the package name, the package foder name and the script Errors at execution time. • JVM initialization errors, Xms or Xmx too small. Adjust these values in the COBJVMINITOPTIONS • Application noXPLINK attempts to call an XPLink class. Check out the _CEE_RUN_OPTS variable. • Exception in main thread. Unresolved link. Check out the structure of the application, the -D variable passed to java • Exception in main thread. Load error. Check out the structure of the application, the -D variable passed to java 24 Cobol and Java 4. The oosample example In this section we won't focus on the various ways to prepare and execute a mixed Cobol and Java application but we'll pay more attention to the structure of such an application. Requirements • The IBM Cobol compiler at level V4 or higher • User has access to the USS The oosample application is installed with the cobol compiler, usually in the usr/lpp/cobol/demo/oosample folder. The JNI copybook is needed. It is usually found in the usr/lpp/cobol/include folder In that section it is assumed the cobol and java sources have been copied to /a/userid/myjava private folder. The sources can also be copied form the next sections. 25 Cobol and Java 4.1. The structure of the application The oosample application is made of these sources: • TestAccounts.cbl main cobol (recursive) • Account.cbl oo cobol routine contains methods createAccount, init, getBalance, credit, debit and print • CheckingAccount.cbl oo cobol routine contains methods createCheckingAccount(2), processCheck and print • Check.java java class contains methods Check, getAmount and getPayee Here's how the application flows. Main program TestAccounts • Invokes Account program to create an instance of the Account object (anAccount) • Invokes methods credit and print of the new Account object anAccount • Invokes CheckingAccount program to create an instance of the CheckingAccount object (aCheckingAccount) • Invokes Check class to create an instance of the Check object (aCheck) • Invokes methods processCheck and print of the new aCheckingAccount object • Invokes print of the object anAccount 26 Cobol and Java 4.2. The Cobol main program TestAccounts.cbl cbl dll,thread,pgmname(longmixed) Identification division. Program-id. "TestAccounts" recursive. Environment division. Configuration section. Repository. Class Account is "Account" Class CheckingAccount is "CheckingAccount" Class Check is "Check". Data Division. Local-storage section. 01 anAccount usage object reference Account. 01 aCheckingAccount usage object reference CheckingAccount. 01 aCheck usage object reference Check. 01 payee usage object reference Account. Procedure division. Test-Account-section. Display "Test Account class" Invoke Account "createAccount" using by value 123456 returning anAccount Invoke anAccount "credit" using by value 500 Invoke anAccount "print" Display space Display "Test CheckingAccount class" Invoke CheckingAccount "createCheckingAccount" using by value 777777 300 returning aCheckingAccount Set payee to anAccount Invoke Check New using by value aCheckingAccount, payee, 125 returning aCheck Invoke aCheckingAccount "processCheck" using by value aCheck Invoke aCheckingAccount "print" Invoke anAccount "print" Stop Run. End program "TestAccounts". Note • Program TestAccount has a Program-id recursive whereas the other programs have a Class-id. • The Repository paragraph defines a class for each of the objects in this application. • The local-storage section specifies storage for each object instance in the application. • Program uses the special 'invoke' statement to execute java based routines. 27 Cobol and Java 28 Cobol and Java 4.3. The Cobol program Account.cbl We first give the Account.cbl source then the java source that cob2 generates. cbl dll,thread,pgmname(longmixed),lib Identification Division. Class-id. Account inherits Base. Environment Division. Configuration section. Repository. Class Base is "java.lang.Object" Class Account is "Account". Identification division. Factory. Data division. Working-storage section. 01 NumberOfAccounts pic 9(6) value zero. Procedure Division. Identification Division. Method-id. "createAccount". Data division. Linkage section. 01 inAccountNumber pic S9(6) binary. 01 outAccount object reference Account. Copy JNI. Procedure Division using by value inAccountNumber returning outAccount. Set address of JNIEnv to JNIEnvPtr Set address of JNINativeInterface to JNIEnv Invoke Account New returning outAccount Invoke outAccount "init" using by value inAccountNumber Add 1 to NumberOfAccounts. End method "createAccount". End Factory. Identification division. Object. Data division. Working-storage section. 01 AccountNumber pic 9(6). 01 AccountBalance pic S9(9) value zero. Procedure Division. Identification Division. Method-id. "init". Data division. Linkage section. 01 inAccountNumber pic S9(9) binary. Procedure Division using by value inAccountNumber. 29 Cobol and Java Move inAccountNumber to AccountNumber. End method "init". Identification Division. Method-id. "getBalance". Data division. Linkage section. 01 outBalance pic S9(9) binary. Procedure Division returning outBalance. Move AccountBalance to outBalance. End method "getBalance". Identification Division. Method-id. "credit". Data division. Linkage section. 01 inCredit pic S9(9) binary. Procedure Division using by value inCredit. Add inCredit to AccountBalance. End method "credit". Identification Division. Method-id. "debit". Data division. Linkage section. 01 inDebit pic S9(9) binary. Procedure Division using by value inDebit. Subtract inDebit from AccountBalance. End method "debit". Identification Division. Method-id. "print". Data division. Local-storage section. 01 PrintableAccountNumber pic ZZZZZZ999999. 01 PrintableAccountBalance pic $$$$,$$$,$$9CR. Procedure Division. Move AccountNumber to PrintableAccountNumber Move AccountBalance to PrintableAccountBalance Display " Account: " PrintableAccountNumber Display " Balance: " PrintableAccountBalance. End method "print". End Object. End class Account. Account.java // PP 5655-S71 IBM Enterprise COBOL for z/OS // 30 4.2.0 Cobol and Java // Generated Java class definition for COBOL class Account // // Date generated: 11/04/2014 // Time generated: 09:55:15 // // ** Do not edit or modify this file! ** // ** It is (and must be) regenerated whenever the ** // ** COBOL class is compiled. ** // public class Account extends java.lang.Object { public native static Account createAccount( int INACCOUNTNUMBER); public native void init( int INACCOUNTNUMBER); public native int getBalance(); public native void credit( int INCREDIT); public native void debit( int INDEBIT); public native void print(); private native static void _classInit(); private java.nio.ByteBuffer Account_instanceData; private native void _instanceDataInit(); public Account(){ Account_instanceData=java.nio.ByteBuffer.allocateDirect(17); _instanceDataInit(); } static { System.loadLibrary("Account"); Account._classInit(); } } Note • The Class-id inherits class Base • The Repository paragraph links Base class to 'java.lang.Object', which is the root of the class hierarchy in Java. It also specifies a class under the same name as the Cobol program so that the cob2 utility generates a Java program under that name. • The Account program begins with a Factory paragraph that contains a 'createAccount' method. This method interfaces with the JVM so the JNI copybook is required. • The Account program then defines the Account object and in the object a number of methods: init, getBalance, credit, debint and print. • The generated java source contains the same elements as the cobol program. 31 Cobol and Java 4.4. The Cobol program CheckingAccount.cbl We first give the cobol source then the java source that cob2 generates. cbl dll,thread,pgmname(longmixed),lib Identification Division. Class-id. CheckingAccount inherits Account. Environment Division. Configuration section. Repository. Class CheckingAccount is "CheckingAccount" Class Check is "Check" Class Account is "Account". Identification division. Factory. Data division. Working-storage section. 01 NumberOfCheckingAccounts pic 9(6) value zero. Procedure Division. Identification Division. Method-id. "createCheckingAccount". Data division. Linkage section. 01 inAccountNumber pic S9(6) binary. 01 outCheckingAccount object reference CheckingAccount. Copy JNI. Procedure Division using by value inAccountNumber returning outCheckingAccount. Set address of JNIEnv to JNIEnvPtr Set address of JNINativeInterface to JNIEnv Invoke CheckingAccount New returning outCheckingAccount Invoke outCheckingAccount "init" using by value inAccountNumber Add 1 to NumberOfCheckingAccounts. End method "createCheckingAccount". Identification Division. Method-id. "createCheckingAccount". Data division. Linkage section. 01 inAccountNumber pic S9(6) binary. 01 inInitialBalance pic S9(9) binary. 01 outCheckingAccount object reference CheckingAccount. Copy JNI. Procedure Division using by value inAccountNumber inInitialBalance returning outCheckingAccount. Set address of JNIEnv to JNIEnvPtr Set address of JNINativeInterface to JNIEnv 32 Cobol and Java Invoke CheckingAccount New returning outCheckingAccount Invoke outCheckingAccount "init" using by value inAccountNumber Invoke outCheckingAccount "credit" using by value inInitialBalance Add 1 to NumberOfCheckingAccounts. End method "createCheckingAccount". End Factory. Identification division. Object. Data division. Working-storage section. 01 CheckFee pic S9(9) value 1. Procedure Division. Identification Division. Method-id. "processCheck". Data division. Local-storage section. 01 amount pic S9(9) binary. 01 payee usage object reference Account. Linkage section. 01 aCheck usage object reference Check. Procedure Division using by value aCheck. Invoke aCheck "getAmount" returning amount Invoke aCheck "getPayee" returning payee Invoke payee "credit" using by value amount Add checkFee to amount Invoke self "debit" using by value amount. End method "processCheck". Identification Division. Method-id. "print". Data division. Local-storage section. 01 printableFee pic $$,$$$,$$9. Procedure Division. Invoke super "print" Move CheckFee to printableFee Display " Check fee: " printableFee. End method "print". End Object. End class CheckingAccount. The CheckingAccount.java source // PP 5655-S71 IBM Enterprise COBOL for z/OS 4.2.0 // // Generated Java class definition for COBOL class CheckingAccount // 33 Cobol and Java // Date generated: 11/04/2014 // Time generated: 09:55:16 // // ** Do not edit or modify this file! ** // ** It is (and must be) regenerated whenever the ** // ** COBOL class is compiled. ** // public class CheckingAccount extends Account { public native static CheckingAccount createCheckingAccount( int INACCOUNTNUMBER); public native static CheckingAccount createCheckingAccount( int INACCOUNTNUMBER, int ININITIALBALANCE); public native void processCheck( Check ACHECK); public native void print(); private native static void _classInit(); private java.nio.ByteBuffer CheckingAccount_instanceData; private native void _instanceDataInit(); public CheckingAccount(){ CheckingAccount_instanceData=java.nio.ByteBuffer.allocateDirect(9); _instanceDataInit(); } static { System.loadLibrary("CheckingAccount"); CheckingAccount._classInit(); } } Note • The remarks about the Account program also apply to the CheckingAccount program. • One difference though, is program ChekingAccount inherits the Account class, not Base. 34 Cobol and Java 4.5. The Check java program public class Check { private CheckingAccount payer; private Account payee; private int amount; public Check(CheckingAccount inPayer, Account inPayee, int inAmount) { payer=inPayer; payee=inPayee; amount=inAmount; } public int getAmount() { return amount; } public Account getPayee() { return payee; } } 35 Cobol and Java 4.6. The oosample.bat script file Create the oosample.bat script file as the below one right in /a/userid/myjava folder. Note the cob2 bdll commands must be single line commands. In the below listings the cob -bdll commnands have been segmented in two lines for an easier reading. # # Script file for the sample OO COBOL and Java application # ----------------------------------------------------------------# The oosample application is made of these sources: # TestAccounts.cbl main cobol (recursive) # Account.cbl oo cobol # CheckingAccount.cbl oo cobol # Check.java java class # ----------------------------------------------------------------# export options are for the execution of the application in Step 7 # ----------------------------------------------------------------# JAVA_HOME is set in the users's .profile # JAVASIDEDECKPATH=${JAVA_HOME}/bin/classic COBOLSIDEDECKPATH=/sys/cobol/V5R1M0/usr/lpp/cobol/lib COBOLCOPYPATH=/sys/cobol/V5R1M0/usr/lpp/cobol/include export COBJVMINITOPTIONS="-Xms1200000 -Xmx1200000 -Xverbosegclog:oosamplelogc.lst" export _CEE_RUNOPTS="XPLINK(ON)" # # Compile TestAccounts.cbl into TestAccounts.o (cob2 -o) # Compile Links TestAccounts.o (cob2 -bdll) # Report TestAccounts.blst # echo '***' echo '*** Step 1 - Compiling and linking TestAccounts cobol program' echo '***' cob2 -c -I${COBOLCOPYPATH} TestAccounts.cbl >TestAccounts.blst cob2 -bdll -o libTestAccounts.so TestAccounts.o ${JAVASIDEDECKPATH}/libjvm.x ${COBOLSIDEDECKPATH}/igzcjava.x >TestAccounts.llst # # Compile Account.cbl into Account.o (cob2 -o) # Compile Links Account.o (cob2 -bdll) # Report Account.blst # echo '***' echo '*** Step 2 -Compiling and linking Account cobol program' echo '***' cob2 -c -bdll -I${COBOLCOPYPATH} Account.cbl cob2 -o libAccount.so -bdll Account.o ${JAVASIDEDECKPATH}/libjvm.x ${COBOLSIDEDECKPATH}/igzcjava.x >Account.blst # # Compile CheckingAccount.cbl no link (cob2 -c) # Compile CheckingAccount.o (cob2 -bdll) # Report CheckingAccount.blst # echo '***' 36 Cobol and Java echo '*** Step 3 -Compiling and linking CheckingAccount cobol program' echo '***' cob2 -c -bdll -I${COBOLCOPYPATH} CheckingAccount.cbl cob2 -o libCheckingAccount.so -bdll CheckingAccount.o ${JAVASIDEDECKPATH}/libjvm.x ${COBOLSIDEDECKPATH}/igzcjava.x >Account.blst # # build Account class # echo '***' echo '*** Step 4 - Compiling Account java program' echo '*** Compiling CheckingAccount java program' echo '*** Compiling Check java program' echo '***' javac Account.java javac CheckingAccount.java javac Check.java # # Execute application # echo '***' echo '*** Step 5 - Execute TstAccounts application' echo '***' ./libTestAccounts.so ## ### End Note • The JAVASIDEDECKPATH, COBOLSIDEDECKPATH and COBOLCOPYPATH variables specify the location of the JAVA and IBM material. The JNI copybook must be available in the cobol/include folder. • From the cobol programs 'libname.so' files are created. The naming convention is that the resulting module must be prefixed with 'lib'. • The last line of the script executes libTestAccounts.so, the top module of the oosample application. 37 Cobol and Java 4.7. Execute the script Type oosample.bat and press Enter. The executables are built and the application executes if no error was encountered. Below is an example of the messages that are produced by the script. .... *** *** Step 3 -Compiling and linking CheckingAccount cobol program *** PP 5655-S71 IBM Enterprise COBOL for z/OS 4.2.0 in progress ... End of compilation 1, class CHECKINGACCOUNT, no statements flagged. IGD01008I ALLOCATION SET TO SCTEMPD M0610 IGD01010I ALLOCATION SET TO SGTEMPD STORAGE GROUP IGD01008I ALLOCATION SET TO SCTEMPD M0610 IGD01010I ALLOCATION SET TO SGTEMPD STORAGE GROUP *** *** Step 4 *** *** *** *** *** Step 5 *** Test Account Account: Balance: Compiling Account java program Compiling CheckingAccount java program Compiling Check java program Execute TstAccounts application class 123456 $500 Test CheckingAccount class Account: 777777 Balance: $174 Check fee: $1 Account: 123456 Balance: $625 38 Chapter 2. Cobol, XML and XSD This chapter presents programs based on the examples in the 'XML Processing on Z/OS' manual and demonstrate the usage of XML oriented cobol statements with validation by a XML Schema definition (XSD file) using the XML System Services (XMLSS) as well as querying the XML System Services. In the below sections we assume the user has allocated a PDS named userid.XML.SOURCE with a DCB=(LREC=80,RECFM=FB,BLKSIZE=4160) It is assumed also user created a folder named 'xml' in his USS environment. 39 Cobol, XML and XSD 1. The XMLCOB1 example References The 'XML Processing in Z/OS manual', chapter 5 How to generate XML, about the XML GENERATE statement The 'XML Processing in Z/OS manual', chapter 8 How to parse XML, about the XML PARSE statement using System Services The 'XML Processing in Z/OS manual', chapter 9 Hints, tips and samples (OSR generation) Requirements • User has access to the TSO/E environment and can execute the IBM Cobol compiler at level V4 or higher • The XML toolkit is available in the USS. • User can start a TSO/E session and has access to the USS 40 Cobol, XML and XSD 1.1. The Cobol program Program XMLCOB1 is not an IBM source. It is supplied to demonstrate how XML generation and XML parsing can be set up in one single program. The goal here is to show that the XML that Cobol generates is well formed and parses with no error. Program XMLCOB1 operates as follows • The harcoded records that are used in conjunction with copybook TSTCOPY to produce the XML are printed. • The XML statements are then generated in a continuous buffer that is printed. • The XML statements are copied one per line to the allocated output. • The XML buffer is parsed back and its elements are printed one per line. For the simplicity of the demonstration the program handles a small amount of data so that only one 32K buffer is needed to hold the XML output. CBL XMLPARSE(XMLSS) IDENTIFICATION DIVISION. PROGRAM-ID. XMLCOB1. *AUTHOR. PATRICE COTTE. DATE-COMPILED. 24/11/14 . ENVIRONMENT DIVISION. CONFIGURATION SECTION. SPECIAL-NAMES. ALPHABET HOST IS EBCDIC C01 IS NEW-PAGE * Define the set of supported characters in both the EBCDIC * and XML english tables. CLASS ebcdic-english-and-xml IS SPACE '.' '<' '(' '+' '|' '&' '!' '$' '*' ')' ';' '-' '/' 'a' thru 'i' 'j' thru 'r' '~' 's' thru 'z' '¬' '[' ']' '{' 'A' thru 'I' '}' 'J' thru 'R' '\' 'S' thru 'Z' '0' thru '9' x'05' x'0D' x'15' x'25' * Use this declaration if using VALIDATING WITH FILE clause XML-SCHEMA MYSCHEMA IS TSTXSD . OBJECT-COMPUTER. IBM-370-Z145. * SOURCE-COMPUTER. IBM DEBUGGING MODE. INPUT-OUTPUT SECTION. FILE-CONTROL. SELECT MYPRINT ASSIGN TO SYSPRINT FILE STATUS IS MYPRINT-STATUS. SELECT TSTXML ASSIGN TO TSTXML 41 Cobol, XML and XSD ORGANIZATION IS SEQUENTIAL FILE STATUS IS TSTXML-STATUS. SELECT TSTXSD ASSIGN TO TSTXSD ORGANIZATION IS SEQUENTIAL FILE STATUS IS TSTXSD-STATUS. DATA DIVISION. FILE SECTION. FD MYPRINT BLOCK CONTAINS 0 TO 3990 CHARACTERS RECORD VARYING IN SIZE FROM 1 TO 133 CHARACTERS DEPENDING ON REC-SIZE LABEL RECORD IS STANDARD DATA RECORD IS FILEREC RECORDING MODE IS V CODE-SET IS HOST. 01 FILEREC. 05 ASA-FILEREC PIC X. 05 DATA-FILEREC PIC X(132). FD 01 FD 01 TSTXML BLOCK CONTAINS 0 TO 4160 CHARACTERS RECORDING MODE F DATA RECORD IS XMLREC. XMLREC PIC X(80). TSTXSD BLOCK CONTAINS 0 TO 4160 CHARACTERS RECORDING MODE F DATA RECORD IS TSTXSD-REC. TSTXSD-REC PIC X(80). / WORKING-STORAGE SECTION. 77 MYPRINT-STATUS 88 OPEN-OK PIC 9(2) VALUE 0. VALUE 0. * 77 77 77 TSTXSD-STATUS TSTXSD-EOF 88 TSTXSD-EOF-HIT 88 TSTXSD-NO-EOF TSTXSD-COUNT PIC 9(2) VALUE 0. PIC X. VALUE 'Y'. VALUE 'N'. PIC 9(4) VALUE 0. TSTXML-STATUS XMLREC-SIZE XMLLEN XMLERR-OFFSET XMLCOUNT XML-PRT-COUNT XML-CODEPAGE XML-CHAR-COUNT XMLPOS TAGSTATE QUOTESTATE PIC 9(2) PIC 9(8) PIC 9(4) PIC 9(4) PIC S9(9) PIC 9(4) PIC 9(4) PIC 9(5) PIC 9(5) PIC 9 PIC 9 * 77 77 77 77 77 77 77 77 77 77 77 * 42 VALUE 0. COMP VALUE 80. VALUE 0. VALUE 0. COMP-4 VALUE 0. VALUE 0. VALUE 1140. COMP-5 VALUE 0. COMP-5 VALUE 0. COMP-5 VALUE 0. COMP-5 VALUE 0. Cobol, XML and XSD 77 01 WS-MSGINFO-INDEX PIC 9(5) COMP. WS-MSGINFO-BLOCK. 03 WS-MSGINFO-BLOCK-ENTRY OCCURS 10 TIMES INDEXED BY WS-MSGINFO-I. 05 WS-MSGINFO-ASA PIC X. 05 WS-MSGINFO-DATA PIC X(80). * 77 77 77 77 77 77 77 * 77 77 77 77 77 77 77 77 77 77 77 77 77 / * ** * 01 01 01 * * * PAGE-COUNT PIC 9(9) COMP VALUE 0. LPERPAGE-COUNT PIC 9(5) COMP VALUE 0. MAX-PER-PAGE PIC 9(5) COMP VALUE 60 . PAGE-OFFSET PIC 9(5) COMP VALUE 110. DATE-OFFSET PIC 9(5) COMP VALUE 105. DATALEN PIC 9(5) COMP VALUE 100. REC-SIZE PIC 9(8) COMP VALUE 133. ZCOUNT:Print field, Pcount:Page count, LCount:Loop count WS-ZCOUNT PIC ZZZZZ9. WS-PCOUNT PIC 9(4) COMP VALUE 0. WS-LCOUNT PIC 9(4) COMP VALUE 0. WS-POS PIC 9(4) COMP VALUE 0. WS-NONZERO-POS PIC 9(9) COMP VALUE 0. WS-NONBLANK-POS PIC 9(9) COMP VALUE 0. WS-LEN PIC 9(9) COMP VALUE 0. WS-COUNT PIC 9(9) VALUE 0. SUBT1 PIC 9(4) COMP VALUE 0. WS-FSTATUS PIC 9(2) VALUE 0. WS-FNAME PIC X(8). WS-SYSID PIC X(4). WS-PRINT PIC X VALUE SPACES. Date/Time areas. WS-DATETIME-HEADER WS-DATE-YYYYMMDD. 10 WS-DATE-CENTURY 10 WS-DATE-YYMMDD. 15 WS-DATE-YEAR 15 WS-DATE-MONTH 15 WS-DATE-DAY WS-DAY-YYYYDDD. 10 WS-DAY-CENTURY 10 WS-DAY-YYDDD. 15 WS-DAY-YEAR 15 WS-DAY-DAY PIC X(40) VALUE SPACES. PIC 9(02) VALUE ZERO. PIC PIC PIC 9(02) 9(02) 9(02) VALUE ZERO. VALUE ZERO. VALUE ZERO. PIC 9(02) VALUE ZERO. PIC PIC 9(02) 9(03) VALUE ZERO. VALUE ZERO. PIC 9 VALUE 1. 1:Monday to 7:Sunday. 01 01 WS-DAY-OF-WEEK WS-TIME. 10 WS-TIME-HH 10 WS-TIME-MM 10 WS-TIME-SS 10 WS-TIME-DD PIC PIC PIC PIC / 43 9(02) 9(02) 9(02) 9(02) VALUE VALUE VALUE VALUE ZERO. ZERO. ZERO. ZERO. Cobol, XML and XSD * * ** Constants * 77 SCALE1 PIC X(49) VALUE ' *----+----1----+----2----+----3----+----4----+-'. 77 SCALE2 PIC X(54) VALUE '---5----+----6----+----7----+----8----+----9----+----0'. / * ** Data record Cobol layout. 01 test-list. 05 test-entry occurs 99 times depending on XMLCOUNT. Copy TSTCOPY. * * * * * * * * * * * ** XML area and fields. The following elements are ignored when the XML definitions are generated: - pointer fields - slack bytes resulting from synchronize - redefinitions - filler The generated area must be 5 to 10 times the size of the input. 77 77 01 generated-length pic s9(4) comp. string-length-pointer pic s9(9) binary value 1. generated-xml-text pic x(32760). 01 01 01 xml-entry-number pic XML-document-length pic XML-doclen-alpha redefines pic XML-element pic 01 s9(4) comp. 999 comp. XML-document-length 9(3). x(132). * Map the XML-CODE special register. 01 XMLCODE. 02 XMLRTN PIC 9(8). 02 XMLRSN PIC 9(8). 01 XMLCODE-BIN PIC 9(9) COMP-5. 01 XMLRTNRSN-BIN redefines XMLCODE-BIN. 02 XMLRTN-BIN PIC 9(4) COMP-5. 02 XMLRSN-BIN PIC 9(4) COMP-5. 01 XMLRTN-MSG PIC X(30). 01 XMLRSN-MSG PIC X(60). * ** SCHEMA area. When using the VALIDATING clause without * the FILE parameter the SCHEMA must be read into this area * prior to the parsing with validation. 01 SCHEMA-AREA PIC X(32760). LINKAGE SECTION. The following system areas start at address 0 and do * 44 Cobol, XML and XSD * 01 01 01 not require a USING in the PROC DIV statement. PSA. 05 FILLER PIC X(16). 05 FLCCVT POINTER. CVT. 05 FILLER PIC X(196). 05 CVTSMCA POINTER. SMCA. 05 FILLER PIC X(16). 05 SMCASID PIC X(4). / PROCEDURE DIVISION. 0000-MAINLINE SECTION. * * Open the Sysprint and print the header. * Open OUTPUT MYPRINT Perform 9000-PRINT-HEADER thru 9000-PRINT-HEADER-EXIT Move MyPrint-Status to WS-FSTATUS Move 'SYSPRINT' to WS-FNAME Perform 9100-PRINT-FS-STATUS thru 9100-PRINT-FS-STATUS-EXIT IF MyPrint-Status > 0 GOBACK END-IF * * 'Read' and validate the input. * Perform 1000-INIT-SECTION Thru 1000-INIT-SECTION-EXIT * * * * * * * * * * * * * * * * The COUNT IN clauses appear no longer valid ? WITH ATTRIBUTES drives the generation of tags such as <name lastn="lastnName1" firstn="firstnName1"> Without the ATTRIBUTES clause the generation would be like <name> <lastn>lastName1</lastn) <firstn>firstName1</firstn> </name> WITH XML-DECLARATION generates the following <?xml version="1.0" encoding="IBM-1140"?> WITH NAMESPACE-PREFIX generates this kind of tag: 45 Cobol, XML and XSD * <abc:name><abc:lastn>lastnName1</abc:lastn> * <abc:firstn>firstnName1</abc:firstn> * Note, a restrction applies, the namespace must be * 'http://www.w3.org/2001/XMLSchema' * XML GENERATE generated-xml-text FROM test-list WITH XML-DECLARATION * WITH attributes * COUNT IN generated-length * NAMESPACE 'http://www.w3.org/2001/XMLSchema' * NAMESPACE-PREFIX 'abc' ON EXCEPTION PERFORM 9220-PRINT-XML-ERROR thru 9220-PRINT-XML-ERROR-EXIT STOP RUN NOT ON EXCEPTION PERFORM 9210-PRINT-XML-OK thru 9210-PRINT-XML-OK-EXIT END-XML. * Guess how much XML has been generated. Perform 8200-GUESS-LENGTH thru 8200-GUESS-LENGTH-EXIT Open OUTPUT TSTXML Perform 9050-PRINT-BLANK-LINE thru 9050-PRINT-BLANK-LINE-EXIT Move TstXML-Status to WS-FSTATUS Move 'TSTXML' to WS-FNAME Perform 9100-PRINT-FS-STATUS thru 9100-PRINT-FS-STATUS-EXIT IF TstXML-Status CLOSE MYPRINT GOBACK END-IF > 0 * Copy the generated text. We copy one tagged entry per line Move 1 to WS-POS Move WS-NONZERO-POS to WS-LEN Move 'Y' to WS-PRINT Perform 9250-COPY-XML thru 9250-COPY-XML-EXIT until WS-LEN > 32760 or WS-Print = 'N' * Print generated-xml-text, one tagged entry per line Move 1 to WS-POS Move 0 to WS-LEN SUBT1 Move 'Y' to WS-PRINT Perform 9200-PRINT-XML thru 9200-PRINT-XML-EXIT until WS-LEN > 32760 46 Cobol, XML and XSD or WS-Print = 'N' Perform 9800-PRINT-XMLEND-MSG thru 9800-PRINT-XMLEND-MSG-EXIT Perform 9050-PRINT-BLANK-LINE thru 9050-PRINT-BLANK-LINE-EXIT * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Parse the generated XML text. -------------------------------------------------------------The following special registers are used by the XML Parsing: Implicit desc Notes XML-EVENT X(30) value spaces. Sending item XML-CODE S9(9) comp value 0. Rc or 0. XML-TEXT Variable length < 16M Sending item generated text. XML-NTEXT Variable length < 16M Sending item generated text (National) Encoding is performed according to the CHAR option. If using the ENCODING clause it must reference a PIC 9(4) variable that contains a valid CCSID: 1208 1047 1140, 37 1141, 1142, 1143, 1144, 1145, 1146, 1147, 1148, 1149, 273 277 278 280 284 285 297 500 871 UTF-8(1) Latin 1 / Open Systems USA, Canada, . . . Euro Country Extended Code Page (ECECP) Austria, Germany ECECP, CECP Denmark, Norway ECECP, CECP Finland, Sweden ECECP, CECP Italy ECECP, CECP Spain, Latin America (Spanish) ECECP, CECP UK ECECP, CECP France ECECP, CECP International ECECP, CECP Iceland ECECP, CECP With VALIDATION clause refers to a FILE entry + SPECIAL NAME If the FILE parameter is omitted the name is an area name and the schema must be read into the area prior to the parsing. -------------------------------------------------------------Perform thru Perform thru 9820-PRINT-STARTXML 9820-PRINT-STARTXML-EXIT 9050-PRINT-BLANK-LINE 9050-PRINT-BLANK-LINE-EXIT * ** In order to parse back the buffer we need to space * ** everything that follows the XML text. WS-NONZERO-POS * ** was computed in the 8200- section. MOVE SPACES to generated-xml-text(WS-NONZERO-POS + 1:) * ** For performance reasons, particularly when the same schema 47 Cobol, XML and XSD * ** is used to validate several file the schema can be loaded * ** into core and the PARSE use the VALIDATING with identifier * ** where identifie is the name of the in-core schema copy. Perform 8400-Read-Schema thru 8400-Read-Schema-Exit. * XML PARSE generated-xml-text ENCODING XML-CODEPAGE VALIDATING WITH FILE MYSCHEMA VALIDATING WITH SCHEMA-AREA PROCESSING PROCEDURE XMLEVENT-HANDLER ON EXCEPTION PERFORM 9860-PRINT-XMLERROR thru 9860-PRINT-XMLERROR-EXIT STOP RUN NOT ON EXCEPTION PERFORM 9840-PRINT-XMLEND-OK thru 9840-PRINT-XMLEND-OK-EXIT END-XML Close TSTXML Close TSTXSD Close MYPRINT . 0000-MAINLINE-EXIT. Goback. 1000-INIT-SECTION. Initialize test-entry (1) Compute XMLCOUNT = XMLCOUNT + 1 MOVE 'XYZ00001' to individual-ID (1) MOVE 'COTTE' to lastname (1) MOVE 'Patrice' to firstname (1) MOVE 'DE' to country-code (1) MOVE 32767 to redbooks-number (1) Compute xml-entry-number = xml-entry-number + 1 * In real life we would read data from some file and possibly * make sure some character fields are acceptable. PERFORM 1030-XML-CHAR-CHECK thru 1030-XML-CHAR-CHECK-EXIT Initialize test-entry (2) Compute XMLCOUNT = XMLCOUNT + 1 MOVE '02A546Z9' to individual-ID (2) MOVE 'GARCIA' to lastname (2) MOVE 'Andy' to firstname (2) MOVE 'DK' to country-code (2) MOVE 1 to redbooks-number (2) Compute xml-entry-number = xml-entry-number + 1 * Make sure the records contain data. PERFORM 1030-XML-CHAR-CHECK thru 48 Cobol, XML and XSD 1030-XML-CHAR-CHECK-EXIT * Print a blank line (or skip if page is full). IF LPERPAGE-COUNT < MAX-PER-PAGE PERFORM 9050-PRINT-BLANK-LINE thru 9050-PRINT-BLANK-LINE-EXIT END-IF . 1000-INIT-SECTION-EXIT. Exit. / * * ** Check out compatibility of a name field with the * ** EBCDIC/XML character table. * ** XMLCOUNT has the rank of the current record. * 1030-XML-CHAR-CHECK. IF LPERPAGE-COUNT + 1 >= MAX-PER-PAGE MOVE 1 to ASA-FILEREC LPERPAGE-COUNT PERFORM 9000-PRINT-HEADER THRU 9000-PRINT-HEADER-EXIT ELSE MOVE SPACE to ASA-FILEREC END-IF MOVE SPACES to DATA-FILEREC MOVE XMLCOUNT to XML-PRT-COUNT IF individual-name (XMLCOUNT) NOT ebcdic-english-and-xml STRING 'Field individual-name (' XML-PRT-COUNT ') ' individual-name(XMLCOUNT) 'is NOT compatible ' 'with the EBCDIC/XML table.' delimited by size into DATA-FILEREC ELSE STRING 'Field individual-name (' XML-PRT-COUNT ') ' individual-name(XMLCOUNT) 'is compatible with ' 'the EBCDIC/XML table.' delimited by size into DATA-FILEREC END-IF WRITE FILEREC COMPUTE LPERPAGE-COUNT = LPERPAGE-COUNT + 1. 1030-XML-CHAR-CHECK-EXIT. EXIT. / ***************************************************************** * Adjust routines 2000-XML-ADJUST * * 2010-XML-ADJUST * ***************************************************************** 2000-XML-ADJUST. 49 Cobol, XML and XSD Move 0 to tagstate quotestate Perform varying XMLPOS from 1 by 1 until XMLPOS > XML-CHAR-COUNT if XMLREC(XMLPOS:1) = '<' move 1 to tagstate end-if if tagstate = 1 if XMLREC(XMLPOS:1) = '"' move 1 to quotestate else move 0 to quotestate end-if end-if if tagstate = 1 and quotestate = 0 Evaluate true When XMLREC(XMLPOS:1) = '-' move '_' to XMLREC(XMLPOS:1) When XMLREC(XMLPOS:1) = '>' move 0 to tagstate When other move function lower-case (XMLREC (XMLPOS:1)) to XMLREC(XMLPOS:1) End-evaluate end-if End-perform. 2000-XML-ADJUST-EXIT. Exit. 2010-XML-ADJUST. Move 0 to tagstate quotestate Perform varying XMLPOS from 1 by 1 until XMLPOS > XML-CHAR-COUNT if DATA-FILEREC(XMLPOS:1) = '<' move 1 to tagstate end-if if tagstate = 1 if DATA-FILEREC(XMLPOS:1) = '"' move 1 to quotestate else move 0 to quotestate end-if end-if 50 Cobol, XML and XSD if tagstate = 1 and quotestate = 0 Evaluate true When DATA-FILEREC(XMLPOS:1) = '-' move '_' to DATA-FILEREC(XMLPOS:1) When DATA-FILEREC(XMLPOS:1) = '>' move 0 to tagstate When other move function lower-case (DATA-FILEREC (XMLPOS:1)) to DATA-FILEREC(XMLPOS:1) End-evaluate end-if End-perform. 2010-XML-ADJUST-EXIT. EXIT. / ***************************************************************** * Print routines 9000-PRINT-HEADER * * 9050-PRINT-BLANK-LINE * * 9100-PRINT-FS-STATUS * * 9200-PRINT-XML * * 9210-PRINT-XML-OK * * 9220-PRINT-XML-ERROR * * 9800-PRINT-XMLEND-MSG * * 9820-PRINT-STARTXML * * 9840-PRINT-XMLEND-OK * * 9860-PRINT-XML-ERROR * ***************************************************************** 9000-PRINT-HEADER. PERFORM 8000-DATE-TIME THRU 8000-DATE-TIME-EXIT PERFORM 8100-GET-SYSID THRU 8100-GET-SYSID-EXIT MOVE SPACES to FILEREC COMPUTE PAGE-COUNT = PAGE-COUNT + 1 MOVE PAGE-COUNT to WS-PCOUNT MOVE 1 to ASA-FILEREC LPERPAGE-COUNT MOVE 'XMLCOB1 Utility v1r0' to DATA-FILEREC MOVE 'Page' to DATA-FILEREC (PAGE-OFFSET:4) MOVE WS-PCOUNT to DATA-FILEREC (PAGE-OFFSET + 6:6) WRITE FILEREC MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE SPACES to FILEREC 'System ' to DATA-FILEREC WS-SYSID to DATA-FILEREC (8:4) '20' to DATA-FILEREC (DATE-OFFSET:2) WS-DATE-YEAR to DATA-FILEREC(DATE-OFFSET '-' to DATA-FILEREC(DATE-OFFSET WS-DATE-MONTH to DATA-FILEREC(DATE-OFFSET '-' to DATA-FILEREC(DATE-OFFSET WS-DATE-DAY to DATA-FILEREC(DATE-OFFSET SPACES to DATA-FILEREC(DATE-OFFSET WS-TIME-HH to DATA-FILEREC(DATE-OFFSET 51 + + + + + + + 2:2) 4:1) 5:2) 7:1) 8:2) 10:2) 12:2) Cobol, XML and XSD MOVE ':' to DATA-FILEREC(DATE-OFFSET + 14:1) MOVE WS-TIME-MM to DATA-FILEREC(DATE-OFFSET + 15:2) WRITE FILEREC COMPUTE LPERPAGE-COUNT = LPERPAGE-COUNT + 1 Perform 9050-PRINT-BLANK-LINE thru 9050-PRINT-BLANK-LINE-EXIT . 9000-PRINT-HEADER-EXIT. EXIT. 9050-PRINT-BLANK-LINE. If LPERPAGE-COUNT + 1 >= MAX-PER-PAGE EXIT End-IF MOVE SPACES to FILEREC WRITE FILEREC COMPUTE LPERPAGE-COUNT = LPERPAGE-COUNT + 1 . 9050-PRINT-BLANK-LINE-EXIT. EXIT. 9100-PRINT-FS-STATUS. COMPUTE WS-COUNT = xml-entry-number + 1 SET WS-MSGINFO-I to 1 MOVE 1 to WS-MSGINFO-INDEX IF WS-FSTATUS not = 00 MOVE SPACES to WS-MSGINFO-DATA(WS-MSGINFO-I) STRING 'XMLCOB1E *** ' WS-FNAME ' File error, file-status: ' WS-FSTATUS delimited by size INTO WS-MSGINFO-DATA(WS-MSGINFO-I) COMPUTE WS-MSGINFO-INDEX = WS-MSGINFO-INDEX + 1 SET WS-MSGINFO-I to WS-MSGINFO-INDEX END-IF * * * MOVE SPACES to FILEREC EVALUATE TRUE Successfull completion .................0----+----1----+----2----+----3----+----4 WHEN WS-FSTATUS = 00 MOVE SPACES to WS-MSGINFO-DATA(WS-MSGINFO-I) STRING 'XMLCOB1I *** File ' DELIMITED by SIZE WS-Fname DELIMITED by SIZE ' successfully opened ' DELIMITED by SIZE into WS-MSGINFO-DATA(WS-MSGINFO-I) MOVE 1 to WS-MSGINFO-INDEX Successfull completion but ... WHEN WS-FSTATUS = 02 STRING 'XMLCOB1I *** Duplicate key condition ' 52 Cobol, XML and XSD * 'when reading or writing an indexed file.' DELIMITED by SIZE into WS-MSGINFO-DATA(WS-MSGINFO-I) MOVE 1 to WS-MSGINFO-INDEX WHEN WS-FSTATUS = 04 STRING 'XMLCOB1I *** The record length does not' ' conform to the fixed file format. ' DELIMITED by SIZE into WS-MSGINFO-DATA(WS-MSGINFO-I) MOVE 1 to WS-MSGINFO-INDEX WHEN WS-FSTATUS = 05 STRING 'XMLCOB1I *** Open successful in I-O or ' 'EXTEND mode, file has been created. ' DELIMITED by SIZE into WS-MSGINFO-DATA(WS-MSGINFO-I) MOVE 1 to WS-MSGINFO-INDEX WHEN WS-FSTATUS = 07 STRING 'XMLCOB1I *** Open for removal or Close ' 'no rewind on a non-reel unit. ' DELIMITED by SIZE into WS-MSGINFO-DATA(WS-MSGINFO-I) MOVE 1 to WS-MSGINFO-INDEX At end conditions WHEN WS-FSTATUS = 10 STRING 'XMLCOB1I *** At end condition on a Read' 'statement. ' DELIMITED by SIZE into WS-MSGINFO-DATA(WS-MSGINFO-I) MOVE 1 to WS-MSGINFO-INDEX WHEN WS-FSTATUS = 34 STRING 'XMLCOB1I *** Permanent error condition ' 'trying to write beyond the file ' 'boundaries.' DELIMITED by SIZE into WS-MSGINFO-DATA(WS-MSGINFO-I) MOVE 1 to WS-MSGINFO-INDEX WHEN WS-FSTATUS = 35 STRING 'XMLCOB1I *** An Open failed on a missing ' 'non optional file.' DELIMITED by SIZE into WS-MSGINFO-DATA(WS-MSGINFO-I) MOVE 1 to WS-MSGINFO-INDEX WHEN WS-FSTATUS = 37 STRING 'XMLCOB1I *** An Open failed because the ' 'open mode is not compatible with the file.' DELIMITED by SIZE into WS-MSGINFO-DATA(WS-MSGINFO-I) MOVE 1 to WS-MSGINFO-INDEX WHEN WS-FSTATUS = 38 STRING 'XMLCOB1I *** An Open failed because the ' 'file has been closed with lock.' DELIMITED by SIZE into WS-MSGINFO-DATA(WS-MSGINFO-I) MOVE 1 to WS-MSGINFO-INDEX 53 Cobol, XML and XSD * * * * * * * * * * * * * * * * * * * WHEN WS-FSTATUS = 39 STRING 'XMLCOB1I *** File Definition is not cons' 'sistent with a Fixed file attributes.' DELIMITED by SIZE into WS-MSGINFO-DATA(WS-MSGINFO-I) MOVE 1 to WS-MSGINFO-INDEX Logic error conditions WHEN WS-FSTATUS = 41 WHEN WS-FSTATUS = 42 WHEN WS-FSTATUS = 43 WHEN WS-FSTATUS = 44 WHEN WS-FSTATUS = 46 WHEN WS-FSTATUS = 47 WHEN WS-FSTATUS = 48 WHEN WS-FSTATUS = 49 Implement other conditions WHEN WS-FSTATUS = 90 WHEN WS-FSTATUS = 91 WHEN WS-FSTATUS = 92 WHEN WS-FSTATUS = 93 WHEN WS-FSTATUS = 94 WHEN WS-FSTATUS = 95 WHEN WS-FSTATUS = 96 WHEN WS-FSTATUS = 97 WHEN WS-FSTATUS = 98 STRING 'XMLCOB1E *** File not allocated under' 'the ddname set in SELECT ... ASSIGN ddname.' DELIMITED by SIZE into WS-MSGINFO-DATA(WS-MSGINFO-I) MOVE 1 to WS-MSGINFO-INDEX WHEN WS-FSTATUS = 99 WHEN OTHER MOVE SPACES TO FILEREC END-EVALUATE IF LPERPAGE-COUNT + WS-MSGINFO-INDEX > MAX-PER-PAGE MOVE 1 to WS-MSGINFO-ASA(1) PERFORM 9000-PRINT-HEADER THRU 9000-PRINT-HEADER-EXIT ELSE MOVE SPACE to WS-MSGINFO-ASA(1) END-IF PERFORM VARYING WS-MSGINFO-I from 1 by 1 Until WS-MSGINFO-I > WS-MSGINFO-INDEX WRITE FILEREC FROM WS-MSGINFO-BLOCK-ENTRY (WS-MSGINFO-I) COMPUTE LPERPAGE-COUNT = LPERPAGE-COUNT + 1 END-PERFORM MOVE SPACES to FILEREC WRITE FILEREC COMPUTE LPERPAGE-COUNT = LPERPAGE-COUNT + 1 . * * The XML buffer is a continuous string. 54 Cobol, XML and XSD * 9100-PRINT-FS-STATUS-EXIT. EXIT. / * ** the XML buffer is a continuous buffer. A binary zero * ** means the end of the XML code has been found. 9200-PRINT-XML. MOVE SPACES to FILEREC IF LPERPAGE-COUNT + 1 >= MAX-PER-PAGE MOVE 1 to ASA-FILEREC LPERPAGE-COUNT PERFORM 9000-PRINT-HEADER THRU 9000-PRINT-HEADER-EXIT ELSE MOVE SPACE to ASA-FILEREC END-IF MOVE generated-xml-text (WS-POS:Length of DATA-FILEREC) to DATA-FILEREC MOVE 0 to SUBT1 INSPECT DATA-FILEREC TALLYING SUBT1 FOR CHARACTERS BEFORE INITIAL x'00' IF SUBT1 < Length of DATA-FILEREC MOVE 'N' to WS-Print INSPECT DATA-FILEREC CONVERTING LOW-VALUES TO SPACE End-If WRITE FILEREC COMPUTE WS-LEN = WS-LEN + Length of DATA-FILEREC COMPUTE WS-POS = WS-POS + Length of DATA-FILEREC COMPUTE LPERPAGE-COUNT = LPERPAGE-COUNT + 1 . 9200-PRINT-XML-EXIT. EXIT. / * ** the XML GENERATE worked with no error. Print success. 9210-PRINT-XML-OK. MOVE SPACES to DATA-FILEREC MOVE 'XMLCOB1I *** XML document was successfully parsed' to DATA-FILEREC WRITE FILEREC COMPUTE LPERPAGE-COUNT = LPERPAGE-COUNT + 1. 9210-PRINT-XML-OK-EXIT. EXIT. / * ** the XML GENERATE failed. Print the error code. 55 Cobol, XML and XSD 9220-PRINT-XML-ERROR. MOVE SPACES to DATA-FILEREC MOVE XML-CODE to XMLCODE-BIN MOVE XMLRTN-BIN to XMLRTN MOVE XMLRSN-BIN to XMLRSN STRING 'XMLCOB1I *** XML parsing failed with the XML Code: ' delimited by size XMLCODE ' RTN=' XMLRTN ' RSN=' XMLRSN delimited by size into DATA-FILEREC WRITE FILEREC COMPUTE LPERPAGE-COUNT = LPERPAGE-COUNT + 1. 9220-PRINT-XML-ERROR-EXIT. EXIT. / * ** the XML buffer is a continuous buffer. Each expression * ** is limited by a '>' end tag.A binary zero means the end * ** of the XML code has been found. 9250-COPY-XML. MOVE SPACES to XMLREC * ** locate the end of a tagged expression. MOVE 0 to SUBT1 INSPECT GENERATED-XML-TEXT (WS-POS: WS-LEN) TALLYING SUBT1 FOR CHARACTERS BEFORE INITIAL '>' * ** When found copy to the print buffer, adjust the lrecl IF SUBT1 > 0 COMPUTE SUBT1 = SUBT1 + 1 MOVE GENERATED-XML-TEXT (WS-POS: SUBT1) TO XMLREC COMPUTE XMLREC-SIZE = SUBT1 * ** Perform additional adjustments: * - change hyphens into undescore * - uppercase element names MOVE SUBT1 to XML-CHAR-COUNT PERFORM 2000-XML-ADJUST thru 2000-XML-ADJUST-EXIT * ** We are now ready to write WRITE XMLREC COMPUTE WS-LEN = WS-LEN - SUBT1 COMPUTE WS-POS = WS-POS + SUBT1 ELSE 56 Cobol, XML and XSD MOVE 'N' to WS-Print END-IF . 9250-COPY-XML-EXIT. EXIT. / * ** Print an XML element as parsed by the XML Parser. 9300-PRINT-XMLPARSED. MOVE SPACES to FILEREC * ** Honor the LPER value but don't print the header on each * ** page. IF LPERPAGE-COUNT + 1 >= MAX-PER-PAGE MOVE 1 to ASA-FILEREC LPERPAGE-COUNT ELSE MOVE SPACE to ASA-FILEREC END-IF MOVE XML-Element (1:Length of DATA-FILEREC) to DATA-FILEREC WRITE FILEREC COMPUTE LPERPAGE-COUNT = LPERPAGE-COUNT + 1 . 9300-PRINT-XMLPARSED-EXIT. EXIT. / 9800-PRINT-XMLEND-MSG. IF LPERPAGE-COUNT + 1 >= MAX-PER-PAGE MOVE 1 to ASA-FILEREC LPERPAGE-COUNT PERFORM 9000-PRINT-HEADER THRU 9000-PRINT-HEADER-EXIT ELSE MOVE SPACE to ASA-FILEREC END-IF perform 9050-PRINT-BLANK-LINE thru 9050-PRINT-BLANK-LINE-EXIT MOVE xml-entry-number to WS-COUNT MOVE SPACES to FILEREC STRING 'XMLCOB1I *** End of XML text reached. ' 'Number of XML entries printed: ' WS-COUNT delimited by size INTO DATA-FILEREC WRITE FILEREC COMPUTE LPERPAGE-COUNT = LPERPAGE-COUNT + 1 57 Cobol, XML and XSD . 9800-PRINT-XMLEND-MSG-EXIT. EXIT. 9820-PRINT-STARTXML. IF LPERPAGE-COUNT + 1 >= MAX-PER-PAGE MOVE 1 to ASA-FILEREC LPERPAGE-COUNT PERFORM 9000-PRINT-HEADER THRU 9000-PRINT-HEADER-EXIT ELSE MOVE SPACE to ASA-FILEREC END-IF perform 9050-PRINT-BLANK-LINE thru 9050-PRINT-BLANK-LINE-EXIT MOVE SPACES to FILEREC STRING 'XMLCOB1I *** Starting to parse the generated XML' delimited by size INTO DATA-FILEREC WRITE FILEREC COMPUTE LPERPAGE-COUNT = LPERPAGE-COUNT + 1 . 9820-PRINT-STARTXML-EXIT. EXIT. / 9840-PRINT-XMLEND-OK. IF LPERPAGE-COUNT + 1 >= MAX-PER-PAGE MOVE 1 to ASA-FILEREC LPERPAGE-COUNT PERFORM 9000-PRINT-HEADER THRU 9000-PRINT-HEADER-EXIT ELSE MOVE SPACE to ASA-FILEREC END-IF perform 9050-PRINT-BLANK-LINE thru 9050-PRINT-BLANK-LINE-EXIT MOVE SPACES to FILEREC STRING 'XMLCOB1I *** XML document was successfully pars delimited by size INTO DATA-FILEREC WRITE FILEREC COMPUTE LPERPAGE-COUNT = LPERPAGE-COUNT + 1 . 9840-PRINT-XMLEND-OK-EXIT. EXIT. / 9860-PRINT-XMLERROR. INITIALIZE WS-MSGINFO-BLOCK MOVE XML-CODE to XMLCODE-BIN MOVE XMLRTN-BIN to XMLRTN MOVE XMLRSN-BIN to XMLRSN 58 Cobol, XML and XSD * COMPUTE WS-MSGINFO-INDEX = 1 SET WS-MSGINFO-I to WS-MSGINFO-INDEX STRING 'XMLCOB1E *** XML document error, XML-CODE : ' XMLCODE delimited by size INTO WS-MSGINFO-DATA(WS-MSGINFO-I) COMPUTE WS-MSGINFO-INDEX = WS-MSGINFO-INDEX + 1 SET WS-MSGINFO-I to WS-MSGINFO-INDEX perform 8300-SET-XMLRTN-MSG thru 8300-SET-XMLRTN-MSG-EXIT STRING 'XMLCOB1E *** XML document error, XML-RTN XMLRTN ' ' XMLRTN-MSG delimited by size INTO WS-MSGINFO-DATA(WS-MSGINFO-I) COMPUTE WS-MSGINFO-INDEX = WS-MSGINFO-INDEX + 1 SET WS-MSGINFO-I to WS-MSGINFO-INDEX STRING 'XMLCOB1E *** XML document error, XML-RSN XMLRSN ' ' XMLRSN-MSG delimited by size INTO WS-MSGINFO-DATA(WS-MSGINFO-I) : ' : ' COMPUTE WS-MSGINFO-INDEX = WS-MSGINFO-INDEX + 1 SET WS-MSGINFO-I to WS-MSGINFO-INDEX STRING 'XMLCOB1E *** XML document error, XML-EVENT:' XML-EVENT (1:30) delimited by size INTO WS-MSGINFO-DATA(WS-MSGINFO-I) COMPUTE WS-MSGINFO-INDEX = WS-MSGINFO-INDEX + 1 SET WS-MSGINFO-I to WS-MSGINFO-INDEX STRING 'XMLCOB1E *** XML document error, XML-TEXT :' XML-TEXT (1:length of DATA-FILEREC - 43) delimited by size INTO WS-MSGINFO-DATA(WS-MSGINFO-I) COMPUTE WS-MSGINFO-INDEX = WS-MSGINFO-INDEX + 1 SET WS-MSGINFO-I to WS-MSGINFO-INDEX MOVE '***' TO WS-MSGINFO-DATA(WS-MSGINFO-I)(XMLERR-OFFSET + 40:3) PERFORM VARYING WS-MSGINFO-I from 1 by 1 Until WS-MSGINFO-I > WS-MSGINFO-INDEX WRITE FILEREC FROM WS-MSGINFO-BLOCK-ENTRY (WS-MSGINFO-I) COMPUTE LPERPAGE-COUNT = LPERPAGE-COUNT + 1 END-PERFORM . 9860-PRINT-XMLERROR-EXIT. EXIT. / ***************************************************************** * Subroutines. 8000-DATE-TIME * 59 Cobol, XML and XSD * 8100-GET-SYSID * * 8200-GUESS-LENGTH * * 8220-GUESS-XSD-LENGTH * * 8300-SET-XMLRTN-MSG * * 8400-READ-SCHEMA * ***************************************************************** 8000-DATE-TIME. ACCEPT WS-TIME FROM TIME ACCEPT WS-DATE-YYMMDD FROM DATE ACCEPT WS-DAY-YYDDD FROM DAY ACCEPT WS-DAY-OF-WEEK FROM DAY-OF-WEEK . 8000-DATE-TIME-EXIT. EXIT. 8100-GET-SYSID. SET Address of PSA to Null SET Address of CVT to flccvt SET Address of SMCA to cvtsmca * The MOVE below is necessary to actually access the SMCASID field * Before that the SMCASID field cannot be used directly. MOVE SMCASID to WS-SYSID . 8100-GET-SYSID-EXIT. EXIT. 8200-GUESS-LENGTH. MOVE 0 to WS-NONZERO-POS PERFORM VARYING WS-POS from 1 by 1 UNTIL WS-POS > 32760 IF generated-xml-text (WS-POS:1) > X'00' COMPUTE WS-NONZERO-POS = WS-NONZERO-POS + 1 END-IF END-PERFORM Perform 9050-PRINT-BLANK-LINE thru 9050-PRINT-BLANK-LINE-EXIT MOVE SPACES to DATA-FILEREC If WS-NONZERO-POS = 0 STRING 'XMLCOB2I *** XML generated buffer is empty! ' delimited by size into DATA-FILEREC Else MOVE WS-NONZERO-POS to WS-ZCOUNT STRING 'XMLCOB2I *** XML generated buffer contains ' WS-ZCOUNT ' bytes.' delimited by size into DATA-FILEREC End-if 60 Cobol, XML and XSD WRITE FILEREC COMPUTE LPERPAGE-COUNT = LPERPAGE-COUNT + 1 If WS-NONZERO-POS = 0 Perform 9800-PRINT-XMLEND-MSG thru 9800-PRINT-XMLEND-MSG-EXIT Close MYPRINT Goback End-if . 8200-GUESS-LENGTH-EXIT. EXIT. / 8300-SET-XMLRTN-MSG. MOVE spaces to XMLRTN-MSG XMLRSN-MSG MOVE 'See the reason code in the XML SS Guide, appendix B' to XMLRSN-MSG Evaluate true when XMLRTN = 0 MOVE 'Successful parsing' to XMLRTN-MSG when XMLRTN = 4 MOVE 'Parsing with warnings' to XMLRTN-MSG when XMLRTN = 8 MOVE 'Parsing has failed' to XMLRTN-MSG when XMLRTN = 12 MOVE 'Document is not well-formed' to XMLRTN-MSG when XMLRTN = 16 MOVE 'Parsing failed w/fatal errorg' to XMLRTN-MSG when XMLRTN = 20 MOVE 'Load of the service failed' to XMLRTN-MSG when XMLRTN = 24 MOVE 'Document not valid w/schema' to XMLRTN-MSG when other CONTINUE End-evaluate . 8300-SET-XMLRTN-MSG-EXIT. EXIT. / 8400-READ-SCHEMA. * ** Open processing Open INPUT TSTXSD Perform 9050-PRINT-BLANK-LINE thru 9050-PRINT-BLANK-LINE-EXIT Move TstXSD-Status to WS-FSTATUS 61 Cobol, XML and XSD Move 'TSTXSD' to WS-FNAME Perform 9100-PRINT-FS-STATUS thru 9100-PRINT-FS-STATUS-EXIT IF TstXSD-Status > 0 CLOSE TSTXML CLOSE MYPRINT GOBACK END-IF Perform 9050-PRINT-BLANK-LINE thru 9050-PRINT-BLANK-LINE-EXIT * ** * ** * ** Read the SCHEMA in the working storage. This is actually the OSR version generated using XSDOSRG utility. This is a compressed file with LRECL=80 Set TSTXSD-NO-EOF to true Compute WS-POS = 1 Initialize Schema-Area Perform until TSTXSD-EOF-HIT READ TSTXSD AT END Set TSTXSD-EOF-HIT to true NOT AT END Move TSTXSD-REC(1:80) to Schema-Area(WS-POS:80) Compute WS-POS = WS-POS + 80 Compute TSTXSD-count = TSTXSD-count + 1 END-READ End-Perform * ** Print the successful message. IF LPERPAGE-COUNT + 1 >= MAX-PER-PAGE MOVE 1 to ASA-FILEREC LPERPAGE-COUNT PERFORM 9000-PRINT-HEADER THRU 9000-PRINT-HEADER-EXIT ELSE MOVE SPACE to ASA-FILEREC END-IF MOVE SPACES to FILEREC STRING 'XMLCOB1I *** End of TSTXSD file reached. ' 'Number of entries read: ' TSTXSD-COUNT delimited by size INTO DATA-FILEREC WRITE FILEREC COMPUTE LPERPAGE-COUNT = LPERPAGE-COUNT + 1 perform 9050-PRINT-BLANK-LINE thru 9050-PRINT-BLANK-LINE-EXIT . 62 Cobol, XML and XSD 8400-READ-SCHEMA-EXIT. EXIT. / ***************************************************************** * XML Parser event handler procedure * * * * While processing the XML document on each event the parser * * detects this procedure is given control with the information * * about the event. * * * * Note the procedure may decide to abort the parsing by * * setting XML-CODE to 1. The parser may decide to abort the * * parsing and informs the procedure by setting XML-EVENT to * * EXCEPTION. * * * ***************************************************************** XMLEVENT-HANDLER SECTION. move spaces to XML-ELEMENT Evaluate XML-EVENT * ** Order XML events most frequent first when 'START-OF-ELEMENT' compute string-length-pointer = 1 String 'ELEM-START: ' '<' XML-TEXT '>' delimited by space into XML-Element with pointer string-length-pointer Perform 9300-PRINT-XMLPARSED thru 9300-PRINT-XMLPARSED-EXIT when 'CONTENT-CHARACTERS' Move 'CONTENTS : ' to XML-Element Move XML-TEXT to XML-Element(12:) Compute xml-document-length = function length(XML-TEXT) Compute string-length-pointer = xml-document-length Perform 9300-PRINT-XMLPARSED thru 9300-PRINT-XMLPARSED-EXIT when 'END-OF-ELEMENT' compute string-length-pointer = 1 String '<ELEM-END : ' '</' XML-TEXT '>' delimited by space into XML-Element with pointer string-length-pointer Perform 9300-PRINT-XMLPARSED Perform 9300-PRINT-XMLPARSED thru 9300-PRINT-XMLPARSED-EXIT when 'ATTRIBUTE-NAME' compute string-length-pointer = 1 String '<ATTRIBUTE: ' '<' XML-TEXT '>' delimited by space into XML-Element with pointer string-length-pointer Perform 9300-PRINT-XMLPARSED thru 9300-PRINT-XMLPARSED-EXIT when 'ATTRIBUTE-CHARACTERS' compute string-length-pointer = 1 63 Cobol, XML and XSD String '<ATTRBCHRS: ' XML-TEXT delimited by size into XML-Element with pointer string-length-pointer Perform 9300-PRINT-XMLPARSED thru 9300-PRINT-XMLPARSED-EXIT when 'ATTRIBUTE-CHARACTER' compute string-length-pointer = 1 String '<ATTRBCHAR: ' XML-TEXT delimited by size into XML-Element with pointer string-length-pointer Perform 9300-PRINT-XMLPARSED thru 9300-PRINT-XMLPARSED-EXIT when 'START-OF-CDATA-SECTION' compute string-length-pointer = 1 String '<CDATA : ' '<' XML-TEXT '>' delimited by space into XML-Element with pointer string-length-pointer Perform 9300-PRINT-XMLPARSED thru 9300-PRINT-XMLPARSED-EXIT when 'END-OF-CDATA-SECTION' compute string-length-pointer = 1 String '<CDATA-END: ' '<' XML-TEXT '>' delimited by space into XML-Element with pointer string-length-pointer Perform 9300-PRINT-XMLPARSED thru 9300-PRINT-XMLPARSED-EXIT when 'CONTENT-CHARACTER' compute string-length-pointer = 1 String '<CNTNCHAR : ' XML-TEXT delimited by space into XML-Element with pointer string-length-pointer Perform 9300-PRINT-XMLPARSED thru 9300-PRINT-XMLPARSED-EXIT when 'PROCESSING-INSTRUCTION-TARGET' compute string-length-pointer = 1 String '<INSTRTGT : ' '<' XML-TEXT '>' delimited by space into XML-Element with pointer string-length-pointer Perform 9300-PRINT-XMLPARSED thru 9300-PRINT-XMLPARSED-EXIT when 'PROCESSING-INSTRUCTION-DATA' compute string-length-pointer = 1 String '<INSTRDATA: ' '<' XML-TEXT '>' delimited by space into XML-Element with pointer string-length-pointer Perform 9300-PRINT-XMLPARSED thru 9300-PRINT-XMLPARSED-EXIT 64 Cobol, XML and XSD when 'COMMENT' compute string-length-pointer = 1 String '<COMMENT: ' '<' XML-TEXT '>' delimited by space into XML-Element with pointer string-length-pointer Perform 9300-PRINT-XMLPARSED thru 9300-PRINT-XMLPARSED-EXIT when 'EXCEPTION' ------------------------------------------------------------Note, the below ranges of exception do not stop the parsing: 1-99 100,001-165,535 200,001-265,535 Decoding of a big XMLCODE: 1. take its hexa value 798818 = x'0C3062' where 2. the first 2 digits are the return code (x'0C' = 12) 3. the two last bytes are the reason code (x'3062') XRSN_CHAR_INVALID * * * * * * * * * * * * * The XMLSS reason-codes are listed in XML System Services Guide * Appendix B. * ------------------------------------------------------------compute string-length-pointer = 1 compute xml-document-length = function length (XML-TEXT) compute xml-document-length = xml-document-length + 1 move xml-code to xmlcode-bin move xml-document-length to xmlerr-offset String 'XMLCOB1E *** Exception at offset ' xmlerr-offset ' text starts with: ' generated-xml-text(xmlerr-offset:) delimited by size into XML-Element with pointer string-length-pointer Perform 9300-PRINT-XMLPARSED thru 9300-PRINT-XMLPARSED-EXIT when other compute string-length-pointer = 1 display 'Unexpected XML event: ' XML-EVENT '.' String '<! Unexpected:' XML-EVENT '>' XMl-EVENT (1:30) delimited by size into XML-Element with pointer string-length-pointer Perform 9300-PRINT-XMLPARSED thru 9300-PRINT-XMLPARSED-EXIT end-evaluate . 65 Cobol, XML and XSD 1.2. The XSD processing The validation of XML data against a Schema file (XSD) requires an OSR file that has been generated from a XSD source. This section shows different ways to generate an OSR file. Here's the XSD source. <?xml version="1.0" encoding="IBM-1140"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <!-- ========================================== --> <!-- List decription --> <!-- ========================================== --> <xs:element name="test-list" type="list_type"/> <!-- ========================================== --> <!-- Main type describes an element of the list --> <!-- ========================================== --> <xs:complexType name="list_type"> <xs:sequence minOccurs="1" maxOccurs="99"> <xs:element name="test-entry" type="entry_type"/> </xs:sequence> </xs:complexType> <!-- ================== --> <!-- Subtypes --> <!-- ================== --> <xs:complexType name="entry_type"> <xs:sequence> <xs:element name="individual-ID" type="xs:string"/> <xs:element name="individual-name" type="name_type"/> <xs:element name="individual-a2" type="a2_type"/> </xs:sequence> </xs:complexType> <xs:complexType name="name_type"> <xs:sequence> <xs:element name="lastname" type="xs:string"/> <xs:element name="firstname" type="xs:string"/> </xs:sequence> </xs:complexType> <xs:complexType name="a2_type"> <xs:sequence> <xs:element name="country-code" type="xs:string"/> <xs:element name="redbooks-number" type="xs:int"/> </xs:sequence> </xs:complexType> </xs:schema> This OSR file can be generated in the USS or in a batch job. • Process a Schema file in the USS. This processing requires the XML toolkit (sys/XML/HXML19x) and the xdsosrg tool available in the path. The xsdosrg tool may have been copied to the /bin folder in the USS along a number of utilities. • Copy this source as tstxsd.xsd in your xml folder 66 Cobol, XML and XSD • In the xml folder type xsdosrg -v -o tstxsd.osr tstxsd.xsd • The resulting OSR file can be copied to a PDS using the command cp txtxsd.osr "//'userid.xml.source(txtxsd)'" • Process a Schema file in a batch job • The xsdosrg module can be copied to a PDSE using the command cp /bin/xsdosrg "//'userid.xml.pdseload(xsdosrg)'" • Alernatively the xdsosrg module can be linked in a batch job and executed //USERIDX JOB accnt,'Gen OSR module',CLASS=A //COPYMOD EXEC PGM=IEWBLINK,PARM='LIST,MAP,CASE=MIXED,NOCALL' //SYSLMOD DD DISP=SHR,DSN=USERID.XML.PDSELOAD(XSDOSRG) //SYSPRINT DD SYSOUT=A //SYSOBJ DD PATH='//bin/xsdosrg',PATHDISP=(KEEP,KEEP) //SYSLIN DD * INCLUDE SYSOBJ ENTRY xsdosrg#C NAME XSDOSRG(R) /* //* //* Execute xsdosrg //* //XSDOSRG EXEC PGM=XSDOSRG, // PARM='/ -v -o /xml/tstxsd.osr xml/tstxsd.xsd' //STEPLIB DD DISP=SHR,DSN=USERID.XML.PDSELOAD // DD DISP=SHR,DSN=SYS1.CSSLIB //ENV DD PATH='/a/userid/xml/xsd2osr.env',PATHOPTS=(ORDONLY), // PATHDISP=(KEEP,KEEP) //CEEOPTS DD * ENVAR("_CEE_ENVFILE=DD:ENV"), RPTOPTS(ON),RPTSTG(ON),POSIX(ON), ANYHEAP(4M,128K,ANYWHERE,FREE), HEAP(92M,256K,ANYWHERE,KEEP,8192,4096) //STDERR DD SYSOUT=* //STDOUT DD SYSOUT=* • Whatever the execution mode the USS must be set up with a number of adequates variables. For this purpose create a xsd2osr.env file right in the xml folder and copy these thrre lines. _BPX_BATCH_UMASK=0022 _BPX_BATCH_SPAWN=YES _BPX_SHAREAS=YES 67 Cobol, XML and XSD The execution of the xdsosrg module in the USS produces messages such as USERID:/a/userid/xml: >xsdosrg -v -o tstxsd.osr tstxsd.xsd OSR file: tstxsd.osr Number of schemas: 1 Schema file: tstxsd.xsd --- Calling gxluInitOSRG ---¨ --- Calling gxluLoadSchema ---¨ #1 --- Calling gxluGenOSR ---¨ Writing the OSR to: tstxsd.osr --- Calling gxluControlOSRG ---¨ --- Calling gxluTermOSRG ---¨ USERID:/a/userid/xml: > 68 Cobol, XML and XSD 1.3. The build of the module and its execution Because all the Cobol options are passed in the cbl statement in the Cobol source there is no specific requirement to compile and link it. A standard Cobol JCL should be enough. The copybook must be available to the Cobol compiler through the SYSLIB allocation. The execution of program XMLCOB1 requires the following • The OSR must be allocated as TSTXSD. The OSR file may be member of a PDS or reside in the USS. • The output goes to TSTXML, a data set with DCB=(LRECL=80,RECFM=FB,BLKSIZE=4160). //useridX //GO //STEPLIB //SYSPRINT //TSTXML //TSTXSD //** TSTXSD //SYSPRINT //SYSIN JOB EXEC DD DD DD DD DD DD DD accnt,'Run module',CLASS)A PGM=XMLCOB1 DISP=SHR,DSN=userid.PDSELOAD SYSOUT=* DISP=SHR,DSN=userid.xml.source(TSTXML) DISP=SHR,DSN=userid.xml.source(TSTOSR3) PATH='/a/userid/xml/tstosr3.xsd' SYSOUT=* DUMMY XMLCOB1 produces a TSTXML output like <?xml version="1.0" encoding="ibm_1140"?> <test_list> <test_entry> <individual_id> XYZ00001</individual_id> <individual_name> <lastname> COTTE</lastname> <firstname> Patrice</firstname> </individual_name> <individual_a2> <country_code> DE</country_code> <redbooks_number> 32767</redbooks_number> </individual_a2> </test_entry> <test_entry> <individual_id> 02A546Z9</individual_id> <individual_name> <lastname> GARCIA</lastname> <firstname> Andy</firstname> 69 Cobol, XML and XSD </individual_name> <individual_a2> <country_code> DK</country_code> <redbooks_number> 1</redbooks_number> </individual_a2> </test_entry> </test_list> XMLCOB1 produces a report as shown below XMLCOB1 Utility v1r0 System XXXX XMLCOB1I *** File SYSPRINT successfully opened Field individual-name (0001) COTTE Field individual-name (0002) GARCIA Patrice Andy XMLCOB1I *** XML document was successfully parsed XMLCOB2I *** XML generated buffer contains XMLCOB1I *** File TSTXML 572 bytes. successfully opened <?xml version="1.0" encoding="IBM-1140"?><test-list><test-entry><individual-ID>XYZ0 TTE</lastname><firstname>Patrice</firstname></individual-name><individual-a2><count redbooks-number></individual-a2></test-entry><test-entry><individual-ID>02A546Z9</i astname><firstname>Andy</firstname></individual-name><individual-a2><country-code>D er></individual-a2></test-entry></test-list> XMLCOB1I *** End of XML text reached. Number of XML entries printed: 000000002 XMLCOB1I *** Starting to parse the generated XML XMLCOB1I *** File TSTXSD successfully opened XMLCOB1I *** End of TSTXSD file reached. Number of entries read: 0266 <! Start of document > </Version:1.0> </Encoding:IBM-1140> ELEM-START:<test-list> ELEM-START:<test-entry> ELEM-START:<individual-ID> CONTENTS :XYZ00001 <ELEM-END</individual-ID> ELEM-START:<individual-name> 70 Cobol, XML and XSD ELEM-START:<lastname> CONTENTS :COTTE <ELEM-END</lastname> ELEM-START:<firstname> CONTENTS :Patrice <ELEM-END</firstname> <ELEM-END</individual-name> ELEM-START:<individual-a2> ELEM-START:<country-code> CONTENTS :DE <ELEM-END</country-code> ELEM-START:<redbooks-number> CONTENTS :32767 <ELEM-END</redbooks-number> <ELEM-END</individual-a2> <ELEM-END</test-entry> ELEM-START:<test-entry> ELEM-START:<individual-ID> CONTENTS :02A546Z9 <ELEM-END</individual-ID> ELEM-START:<individual-name> ELEM-START:<lastname> CONTENTS :GARCIA <ELEM-END</lastname> ELEM-START:<firstname> CONTENTS :Andy <ELEM-END</firstname> <ELEM-END</individual-name> ELEM-START:<individual-a2> ELEM-START:<country-code> CONTENTS :DK <ELEM-END</country-code> ELEM-START:<redbooks-number> CONTENTS :1 <ELEM-END</redbooks-number> <ELEM-END</individual-a2> <ELEM-END</test-entry> <ELEM-END</test-list> <! End of document > XMLCOB1I *** XML document was successfully parsed. 71 Cobol, XML and XSD 2. The XMLQRY1 example This program is based on the example in Appendix B.4 of the 'IBM XML for Z/OS processing' manual. The XML System Services can be invoked for other purposes than parsing an XML stream. This program calls program GXL1QXD to query information about the XML stream and environment. Reference The XML Processing in Z/OS manual, Chapter 8 The XML Processing in Z/OS manual, Appendix B.4 Requirements • User has access to the TSO/E environment and can execute the IBM Cobol compiler at level V4 or higher 72 Cobol, XML and XSD 2.1. The Cobol program Program XMLQRY1 operates as follows • The TSTXML input is printed one record per line. • On each read the record is concatenated to the existing QXD input buffer. • Program calls the XML System Services querying information from the XML document declaration. • The QXD output information is printed one item per line. CBL XMLPARSE(XMLSS) IDENTIFICATION DIVISION. PROGRAM-ID. XMLQRY1. *AUTHOR. PATRICE COTTE. * ------------------------------------------------ OK -* IBM XML FOR ZOS PROCESSING. * Appendix B.4, Cobol example. * * This program calls the zOS XML System services to query * the XML document declaration. * * This program reads from file TSTXML as many times * as required to fill the 4K input-buffer. TSTXML is * defined as F/4160. It can be the output of program * XMLCOB1 * * The output buffer is also a 4K buffer. * * Return-code Reason-code * 4 1301 End of input buffer * 8 1302 Output buffer small * 4 1303 Output buffer ended * 4 1304 Input and Output buffers end * * -----------------------------------------------------*INSTALLATION. *DATE-MODIFIED. DATE-COMPILED. 05/12/14 . ENVIRONMENT DIVISION. CONFIGURATION SECTION. SPECIAL-NAMES. ALPHABET HOST IS EBCDIC C01 IS NEW-PAGE. OBJECT-COMPUTER. IBM-370-Z145. * SOURCE-COMPUTER. IBM DEBUGGING MODE. INPUT-OUTPUT SECTION. FILE-CONTROL. SELECT TSTXML ASSIGN TO TSTXML ORGANIZATION IS SEQUENTIAL FILE STATUS IS TSTXML-STATUS. 73 Cobol, XML and XSD SELECT MYPRINT ASSIGN TO SYSPRINT FILE STATUS IS MYPRINT-STATUS. DATA DIVISION. FILE SECTION. FD TSTXML BLOCK CONTAINS 0 TO 4160 CHARACTERS RECORDING MODE F DATA RECORD IS TSTXML-REC CODE-SET IS HOST. 01 TSTXML-REC PIC X(80). FD 01 MYPRINT RECORDING MODE IS V BLOCK CONTAINS 0 TO 3990 CHARACTERS RECORD VARYING IN SIZE FROM 1 TO 133 CHARACTERS DEPENDING ON REC-SIZE LABEL RECORD IS STANDARD DATA RECORD IS FILEREC CODE-SET IS HOST. FILEREC. 05 ASA-FILEREC PIC X. 05 DATA-FILEREC PIC X(132). / WORKING-STORAGE SECTION. 77 MyPRINT-STATUS PIC 9(2) VALUE 0. 77 TSTXML-STATUS PIC 9(2) VALUE 0. 88 OPEN-OK VALUE 0. 77 TSTXML-RECSIZE PIC 9(4) COMP VALUE 80. 77 WS-MSGINFO-INDEX PIC 9(5) COMP. 01 WS-MSGINFO-BLOCK. 03 WS-MSGINFO-LL PIC 9(9) COMP VALUE 0. 03 WS-MSGINFO-BLOCK-ENTRY OCCURS 10 TIMES INDEXED BY WS-MSGINFO-I. 05 WS-MSGINFO-ASA PIC X. 05 WS-MSGINFO-DATA PIC X(80). 77 PAGE-COUNT PIC 9(9) COMP VALUE 0. 77 LPERPAGE-COUNT PIC 9(5) COMP VALUE 0. 77 MAX-PER-PAGE PIC 9(5) COMP VALUE 60 . 77 PAGE-OFFSET PIC 9(5) COMP VALUE 110. 77 DATE-OFFSET PIC 9(5) COMP VALUE 105. 77 DATALEN PIC 9(5) COMP VALUE 100. 77 REC-SIZE PIC 9(8) COMP VALUE 133. 77 XMLREC-SIZE PIC 9(8) COMP VALUE 1020. * ZCOUNT:Print field, Pcount:Page count, LCount:Loop count 77 WS-ZCOUNT PIC ZZZZZ9. 77 WS-PCOUNT PIC 9(4) COMP VALUE 0. 77 WS-LCOUNT PIC 9(4) COMP VALUE 0. 77 WS-COUNT PIC 9(8) VALUE 0. 77 WS-POS PIC 9(4) COMP VALUE 0. 77 WS-NONZERO-POS PIC 9(9) COMP VALUE 0. 77 WS-LEN PIC 9(9) COMP VALUE 0. 77 SUBT1 PIC 9(4) COMP VALUE 0. 77 WS-PRINT PIC X VALUE SPACES. 74 Cobol, XML and XSD 77 77 77 01 / * ** * 01 01 01 * * * WS-STATUS WS-FNAME WS-SYSID Ws-Misc. 05 rc 05 length-pointer 05 XMLSS-PGM 05 End-Of-File PIC PIC PIC Pic Pic Pic Pic 9(2) VALUE 0. X(8). X(4). s9(9) binary value 0. s9(9) binary value 1. x(8) value "GXL1QXD". x value space. Date/Time areas. WS-DATETIME-HEADER WS-DATE-YYYYMMDD. 10 WS-DATE-CENTURY 10 WS-DATE-YYMMDD. 15 WS-DATE-YEAR 15 WS-DATE-MONTH 15 WS-DATE-DAY WS-DAY-YYYYDDD. 10 WS-DAY-CENTURY 10 WS-DAY-YYDDD. 15 WS-DAY-YEAR 15 WS-DAY-DAY PIC X(40) VALUE SPACES. PIC 9(02) VALUE ZERO. PIC PIC PIC 9(02) 9(02) 9(02) VALUE ZERO. VALUE ZERO. VALUE ZERO. PIC 9(02) VALUE ZERO. PIC PIC 9(02) 9(03) VALUE ZERO. VALUE ZERO. PIC 9 VALUE 1. 1:Monday to 7:Sunday. 01 01 WS-DAY-OF-WEEK WS-TIME. 10 WS-TIME-HH 10 WS-TIME-MM 10 WS-TIME-SS 10 WS-TIME-DD PIC PIC PIC PIC 9(02) 9(02) 9(02) 9(02) VALUE VALUE VALUE VALUE ZERO. ZERO. ZERO. ZERO. / * * ** Constants * 77 SCALE1 PIC X(49) VALUE ' *----+----1----+----2----+----3----+----4----+-'. 77 SCALE2 PIC X(54) VALUE '---5----+----6----+----7----+----8----+----9----+----0'. / * * ** QXD area and fields. * 01 QXD-Input. 03 QXD-Input-Structure. 05 QXD-Input-Workarea Pic x(32768). 05 QXD-Input-Workarea-Length Pic s9(9) binary. * ** Safe estimate for our XML example. 05 QXD-Input-Buffer Pic x(3000). 05 QXD-Input-Buffer-Length Pic s9(9) binary. 05 QXD-Output-Pointer Usage is pointer. 05 QXD-Return-Code Pic s9(9) binary. 75 Cobol, XML and XSD 05 01 01 01 * * 01 01 01 QXD-Reason-code Pic s9(9) binary. QXD-Return-codes. 05 QXD-Retcode 88 QXD-success QXD-Output-Display. 05 QXD-Version 05 QXD-xml-Autodet-Value 05 QXD-xml-Autodet-ccsid 05 QXD-xml-version 05 QXD-xml-release 05 QXD-xml-spec-ccsid 05 QXD-xml-flag1 05 QXD-xml-flag2 05 QXD-xml-reserved 05 QXD-xml-decl-length Pic s9(9) binary. Value 0. Pic Pic Pic Pic Pic Pic Pic Pic Pic Pic zzzz9. zzzz9. zzzz9. zzzz9. zzzz9. zzzz9. x. x. zzzz9. zzzz9. XML-Doc-Len Pic 9(8) COMP VALUE 1020. LINKAGE SECTION. The following system areas start at address 0 and do not require a USING in the PROC DIV statement. PSA. 05 FILLER PIC X(16). 05 FLCCVT POINTER. CVT. 05 FILLER PIC X(196). 05 CVTSMCA POINTER. SMCA. 05 FILLER PIC X(16). 05 SMCASID PIC X(4). / 01 * QXD-Output-STRUCTURE. COPY GXLYQXD. 05 QXD-Version 05 QXD-XML-Autodet-Value 05 QXD-XML-Autodet-CCSID 05 QXD-XML-Version 05 QXD-XML-Release 05 QXD-XML-Spec-CCSID 05 QXD-XML-Flag1 05 QXD-XML-Flag2 05 QXD-XML-Reserved 05 QXD-Decl-Length pic pic pic pic pic pic pic pic pic pic 9(9) 9(9) 9(9) 9(4) 9(4) 9(9) x. x. 9(4) 9(9) comp-5. comp-5. comp-5. comp-5. comp-5. comp-5. comp-5. comp-5. PROCEDURE DIVISION. 0000-MAINLINE SECTION. Move Low-values to QXD-Input-Workarea Move 32768 to QXD-Input-Workarea-Length Move 0 to QXD-Return-Code QXD-Reason-code Initialize QXD-Output-Display. Open OUTPUT MYPRINT 76 Cobol, XML and XSD Perform 9000-PRINT-HEADER thru 9000-PRINT-HEADER-EXIT Move MYPRINT-STATUS to WS-STATUS Move 'SYSPRINT' to WS-FNAME Perform 9100-PRINT-FS-STATUS thru 9100-PRINT-FS-STATUS-EXIT IF MYPRINT-STATUS > GOBACK END-IF 0 Open INPUT TstXML Move TSTXML-STATUS to WS-STATUS Move 'TSTXML' to WS-FNAME Perform 9100-PRINT-FS-STATUS thru 9100-PRINT-FS-STATUS-EXIT IF TSTXML-STATUS Close MYPRINT GOBACK END-IF * ** > 0 Read the XML document entirely into our buffer. Initialize QXD-Input-Buffer Initialize QXD-Input-Buffer-Length Perform Read-XML-Doc thru Read-Exit Move 1 to Length-pointer Perform String-XML-data thru String-exit until End-Of-file = "Y" Perform 9050-PRINT-BLANK-LINE thru 9050-PRINT-BLANK-LINE-EXIT Perform 9200-PRINT-QXD-INPUT thru 9200-PRINT-QXD-INPUT-EXIT Perform 9050-PRINT-BLANK-LINE thru 9050-PRINT-BLANK-LINE-EXIT Perform 9050-PRINT-BLANK-LINE thru 9050-PRINT-BLANK-LINE-EXIT * ** Call zOS System services. Call XMLSS-PGM using QXD-Input-Workarea QXD-Input-Workarea-Length QXD-Input-Buffer QXD-Input-Buffer-Length QXD-Output-Pointer 77 Cobol, XML and XSD QXD-Return-Code QXD-Reason-code returning rc Set address of QXD-Output-structure to QXD-Output-pointer COMPUTE length-pointer = 1 MOVE SPACES to FILEREC MOVE WS-COUNT to WS-ZCOUNT STRING 'XMLQRY1I *** XML Parser results follow:' DELIMITED BY SIZE INTO DATA-FILEREC WITH POINTER length-pointer IF LPERPAGE-COUNT + 1 >= MAX-PER-PAGE MOVE 1 to ASA-FILEREC LPERPAGE-COUNT END-IF COMPUTE REC-SIZE = length-pointer WRITE FILEREC COMPUTE LPERPAGE-COUNT = LPERPAGE-COUNT + 1 * ** If the System Services failed, say so. If rc > 0 Perform 9050-PRINT-BLANK-LINE thru 9050-PRINT-BLANK-LINE-EXIT Move QXD-Return-Code to WS-ZCOUNT Compute length-pointer = 1 String "Return-code: " WS-ZCOUNT delimited by space into DATA-FILEREC with pointer length-pointer if lperpage-count + 1 >= max-per-page move 1 to asa-filerec lperpage-count end-if Compute rec-size = length-pointer Write FILEREC Compute lperpage-count = lperpage-count + 1 Move QXD-Reason-code to WS-ZCOUNT compute length-pointer = 1 String "Reason-code: " WS-ZCOUNT delimited by space into DATA-FILEREC with pointer length-pointer if lperpage-count + 1 >= max-per-page move 1 to asa-filerec lperpage-count end-if Compute rec-size = length-pointer Write FILEREC Compute lperpage-count = lperpage-count + 1 Stop run End-If 78 Cobol, XML and XSD * ** We are good, start reporting! Evaluate QXD-Return-code When 0 Set address of QXD-Output-structure to QXD-Output-pointer Move corresponding QXD-Output-Structure to QXD-Output-Display Perform thru Perform thru 9050-PRINT-BLANK-LINE 9050-PRINT-BLANK-LINE-EXIT 9050-PRINT-BLANK-LINE 9050-PRINT-BLANK-LINE-EXIT Compute length-pointer = 1 String "QXD version : " QXD-Version of QXD-Output-Display delimited by size into DATA-FILEREC with pointer length-pointer if lperpage-count + 1 >= max-per-page move 1 to asa-filerec lperpage-count end-if Compute Rec-size = length-pointer Write FILEREC Compute lperpage-count = lperpage-count + 1 Compute length-pointer = 1 String "XML Autodet Value : " QXD-XML-Autodet-value of QXD-Output-Display delimited by size into DATA-FILEREC with pointer length-pointer if lperpage-count + 1 >= max-per-page move 1 to asa-filerec lperpage-count end-if Compute Rec-size = length-pointer Write FILEREC Compute lperpage-count = lperpage-count + 1 Compute length-pointer = 1 String "XML Autodet CCSID : " QXD-XML-Autodet-CCSID of QXD-Output-Display delimited by size into DATA-FILEREC with pointer length-pointer if lperpage-count + 1 >= max-per-page move 1 to asa-filerec lperpage-count end-if Compute Rec-size = length-pointer Write FILEREC Compute lperpage-count = lperpage-count + 1 Compute length-pointer = 1 79 Cobol, XML and XSD String "XML Version : " QXD-XML-Version of QXD-Output-Display delimited by size into DATA-FILEREC with pointer length-pointer if lperpage-count + 1 >= max-per-page move 1 to asa-filerec lperpage-count end-if Compute Rec-size = length-pointer Write FILEREC Compute lperpage-count = lperpage-count + 1 Compute length-pointer = 1 String "XML Release : " QXD-XML-Release of QXD-Output-Display delimited by size into DATA-FILEREC with pointer length-pointer if lperpage-count + 1 >= max-per-page move 1 to asa-filerec lperpage-count end-if Compute Rec-size = length-pointer Write FILEREC Compute lperpage-count = lperpage-count + 1 Compute length-pointer = 1 String "XML Spec CCSID : " QXD-XML-Spec-CCSID of QXD-Output-Display delimited by size into DATA-FILEREC with pointer length-pointer if lperpage-count + 1 >= max-per-page move 1 to asa-filerec lperpage-count end-if Compute Rec-size = length-pointer Write FILEREC Compute lperpage-count = lperpage-count + 1 Compute length-pointer = 1 String "XML Flag 1 : " QXD-XML-Flag1 of QXD-Output-Display delimited by size into DATA-FILEREC with pointer length-pointer if lperpage-count + 1 >= max-per-page move 1 to asa-filerec lperpage-count end-if Compute Rec-size = length-pointer Write FILEREC Compute lperpage-count = lperpage-count + 1 Compute length-pointer = 1 String "XML Flag 2 : " 80 Cobol, XML and XSD QXD-XML-Flag2 of QXD-Output-Display delimited by size into DATA-FILEREC with pointer length-pointer if lperpage-count + 1 >= max-per-page move 1 to asa-filerec lperpage-count end-if Compute Rec-size = length-pointer Write FILEREC Compute lperpage-count = lperpage-count + 1 Compute length-pointer = 1 String "XML Reserved : " QXD-XML-Reserved of QXD-Output-Display delimited by size into DATA-FILEREC with pointer length-pointer if lperpage-count + 1 >= max-per-page move 1 to asa-filerec lperpage-count end-if Compute Rec-size = length-pointer Write FILEREC Compute lperpage-count = lperpage-count + 1 Compute length-pointer = 1 String "XML Decl Length : " QXD-XML-Decl-Length of QXD-Output-Display delimited by size into DATA-FILEREC with pointer length-pointer if lperpage-count + 1 >= max-per-page move 1 to asa-filerec lperpage-count end-if Compute Rec-size = length-pointer Write FILEREC Compute lperpage-count = lperpage-count + 1 Perform 9050-PRINT-BLANK-LINE thru 9050-PRINT-BLANK-LINE-EXIT End-Evaluate Perform thru Perform thru 9050-PRINT-BLANK-LINE 9050-PRINT-BLANK-LINE-EXIT 9800-PRINT-ENDMSG 9800-PRINT-ENDMSG-EXIT Close TstXML Close MYPRINT . 0000-MAINLINE-EXIT. Goback. 81 Cobol, XML and XSD Read-XML-Doc. Read TSTXML AT END Move "Y" to End-Of-File Move TSTXML-STATUS to WS-STATUS Perform 9150-PRINT-INPUT-SIZE thru 9150-PRINT-INPUT-SIZE-EXIT End-Read Compute Ws-Count = WS-Count + 1 . Read-Exit. Exit. String-XML-Data. Scan backwards a record until '>' is found and compute the text size in XMLREC-size. Initialize SUBT1 Inspect function reverse (TSTXML-Rec) tallying SUBT1 for characters before initial '>' Compute XMLREC-Size = TSTXML-Recsize - SUBT1 * * * Add Length of TSTXML record to QXD-Input-Buffer-Length Add XMLREC-size to QXD-Input-Buffer-Length * Append the current record to the QXD buffer. String TSTXML-REC (1:XMLREC-size) delimited by size into QXD-Input-Buffer with Pointer Length-pointer. * Continue reading till end of file. Perform Read-XML-Doc thru Read-Exit . String-Exit. Exit. / ***************************************************************** * Print routines 9000-PRINT-HEADER * * 9050-PRINT-BLANK-LINE * * 9100-PRINT-FS-STATUS * * 9150-PRINT-INPUT-SIZE * * 9800-PRINT-ENDMSG * ***************************************************************** 9000-PRINT-HEADER. PERFORM 8000-DATE-TIME THRU 8000-DATE-TIME-EXIT PERFORM 8100-GET-SYSID THRU 8100-GET-SYSID-EXIT MOVE SPACES to FILEREC COMPUTE PAGE-COUNT = PAGE-COUNT + 1 MOVE PAGE-COUNT to WS-PCOUNT 82 Cobol, XML and XSD MOVE 1 to ASA-FILEREC LPERPAGE-COUNT MOVE 'XMLQRY1 Utility v1r0' to DATA-FILEREC MOVE 'Page' to DATA-FILEREC (PAGE-OFFSET:4) MOVE WS-PCOUNT to DATA-FILEREC (PAGE-OFFSET + 6:6) COMPUTE REC-SIZE = PAGE-OFFSET + 6 + 6 WRITE FILEREC MOVE SPACES to FILEREC MOVE 'System ' to DATA-FILEREC MOVE WS-SYSID to DATA-FILEREC (8:4) MOVE '20' to DATA-FILEREC (DATE-OFFSET:2) MOVE WS-DATE-YEAR to DATA-FILEREC(DATE-OFFSET MOVE '-' to DATA-FILEREC(DATE-OFFSET MOVE WS-DATE-MONTH to DATA-FILEREC(DATE-OFFSET MOVE '-' to DATA-FILEREC(DATE-OFFSET MOVE WS-DATE-DAY to DATA-FILEREC(DATE-OFFSET MOVE SPACES to DATA-FILEREC(DATE-OFFSET MOVE WS-TIME-HH to DATA-FILEREC(DATE-OFFSET MOVE ':' to DATA-FILEREC(DATE-OFFSET MOVE WS-TIME-MM to DATA-FILEREC(DATE-OFFSET COMPUTE REC-SIZE = DATE-OFFSET + 15 + 2 WRITE FILEREC COMPUTE LPERPAGE-COUNT = LPERPAGE-COUNT + 1 MOVE SPACES to FILEREC COMPUTE REC-SIZE = 1 WRITE FILEREC COMPUTE LPERPAGE-COUNT = LPERPAGE-COUNT + 1 . 9000-PRINT-HEADER-EXIT. EXIT. 9050-PRINT-BLANK-LINE. MOVE SPACES to FILEREC COMPUTE REC-SIZE = 1 IF LPERPAGE-COUNT + 1 >= MAX-PER-PAGE EXIT ELSE WRITE FILEREC COMPUTE LPERPAGE-COUNT = LPERPAGE-COUNT + 1 END-IF . 9050-PRINT-BLANK-LINE-EXIT. EXIT. 9100-PRINT-FS-STATUS. SET WS-MSGINFO-I to 1 MOVE 1 to WS-MSGINFO-INDEX length-pointer IF WS-STATUS not = 00 MOVE SPACES to WS-MSGINFO-DATA(WS-MSGINFO-I) STRING 'XMLQRY1E *** ' WS-FNAME ' File error, file-status: ' 83 + + + + + + + + + 2:2) 4:1) 5:2) 7:1) 8:2) 10:2) 12:2) 14:1) 15:2) Cobol, XML and XSD WS-STATUS delimited by size INTO WS-MSGINFO-DATA(WS-MSGINFO-I) with pointer length-pointer COMPUTE WS-MSGINFO-LL = length-pointer COMPUTE WS-MSGINFO-INDEX = WS-MSGINFO-INDEX + 1 SET WS-MSGINFO-I to WS-MSGINFO-INDEX END-IF * * * * MOVE SPACES to FILEREC EVALUATE TRUE Successfull completion .................0----+----1----+----2----+----3----+----4 WHEN WS-STATUS = 00 MOVE SPACES to WS-MSGINFO-DATA(WS-MSGINFO-I) STRING 'XMLQRY1I *** File ' WS-FNAME ' successfully opened.' DELIMITED by SIZE into WS-MSGINFO-DATA(WS-MSGINFO-I) with pointer length-pointer MOVE 1 to WS-MSGINFO-INDEX Successfull completion but ... WHEN WS-STATUS = 02 STRING 'XMLQRY1I *** Duplicate key condition ' 'when reading or writing an indexed file.' DELIMITED by SIZE into WS-MSGINFO-DATA(WS-MSGINFO-I) with pointer length-pointer MOVE 1 to WS-MSGINFO-INDEX WHEN WS-STATUS = 04 STRING 'XMLQRY1I *** The record length does not' ' conform to the fixed file format. ' DELIMITED by SIZE into WS-MSGINFO-DATA(WS-MSGINFO-I) with pointer length-pointer MOVE 1 to WS-MSGINFO-INDEX WHEN WS-STATUS = 05 STRING 'XMLQRY1I *** Open successful in I-O or ' 'EXTEND mode, file has been created. ' DELIMITED by SIZE into WS-MSGINFO-DATA(WS-MSGINFO-I) with pointer length-pointer MOVE 1 to WS-MSGINFO-INDEX WHEN WS-STATUS = 07 STRING 'XMLQRY1I *** Open for removal or Close ' 'no rewind on a non-reel unit. ' DELIMITED by SIZE into WS-MSGINFO-DATA(WS-MSGINFO-I) with pointer length-pointer MOVE 1 to WS-MSGINFO-INDEX At end conditions WHEN WS-STATUS = 10 STRING 'XMLQRY1I *** At end condition on a Read' 'statement. ' DELIMITED by SIZE 84 Cobol, XML and XSD * * * * * * * * * * into WS-MSGINFO-DATA(WS-MSGINFO-I) with pointer length-pointer MOVE 1 to WS-MSGINFO-INDEX WHEN WS-STATUS = 34 STRING 'XMLQRY1I *** Permanent error condition ' 'trying to write beyond the file ' 'boundaries.' DELIMITED by SIZE into WS-MSGINFO-DATA(WS-MSGINFO-I) with pointer length-pointer MOVE 1 to WS-MSGINFO-INDEX WHEN WS-STATUS = 35 STRING 'XMLQRY1I *** An Open failed on a missing ' 'non optional file.' DELIMITED by SIZE into WS-MSGINFO-DATA(WS-MSGINFO-I) with pointer length-pointer MOVE 1 to WS-MSGINFO-INDEX WHEN WS-STATUS = 37 STRING 'XMLQRY1I *** An Open failed because the ' 'open mode is not compatible with the file.' DELIMITED by SIZE into WS-MSGINFO-DATA(WS-MSGINFO-I) with pointer length-pointer MOVE 1 to WS-MSGINFO-INDEX WHEN WS-STATUS = 38 STRING 'XMLQRY1I *** An Open failed because the ' 'file has been closed with lock.' DELIMITED by SIZE into WS-MSGINFO-DATA(WS-MSGINFO-I) with pointer length-pointer MOVE 1 to WS-MSGINFO-INDEX WHEN WS-STATUS = 39 STRING 'XMLQRY1I *** File Definition is not cons' 'sistent with a Fixed file attributes.' DELIMITED by SIZE into WS-MSGINFO-DATA(WS-MSGINFO-I) with pointer length-pointer MOVE 1 to WS-MSGINFO-INDEX Logic error conditions WHEN WS-STATUS = 41 WHEN WS-STATUS = 42 WHEN WS-STATUS = 43 WHEN WS-STATUS = 44 WHEN WS-STATUS = 46 WHEN WS-STATUS = 47 WHEN WS-STATUS = 48 WHEN WS-STATUS = 49 Implementor defined condition WHEN WS-STATUS = 90 STRING 'XMLQRY1I *** File Definition is not cons' 'sistent with the actual file organization ' 'about the record type.' DELIMITED by SIZE 85 Cobol, XML and XSD * * * * * * * * * into WS-MSGINFO-DATA(WS-MSGINFO-I) with pointer length-pointer MOVE 1 to WS-MSGINFO-INDEX WHEN WS-STATUS = 91 WHEN WS-STATUS = 92 WHEN WS-STATUS = 93 WHEN WS-STATUS = 94 WHEN WS-STATUS = 95 WHEN WS-STATUS = 96 WHEN WS-STATUS = 97 WHEN WS-STATUS = 98 WHEN WS-STATUS = 99 WHEN OTHER CONTINUE END-EVALUATE * ** save message size for later printing COMPUTE WS-MSGINFO-LL = length-pointer IF LPERPAGE-COUNT + WS-MSGINFO-INDEX > MAX-PER-PAGE MOVE 1 to WS-MSGINFO-ASA(1) PERFORM 9000-PRINT-HEADER THRU 9000-PRINT-HEADER-EXIT ELSE MOVE SPACE to WS-MSGINFO-ASA(1) END-IF MOVE WS-MSGINFO-LL to REC-SIZE PERFORM VARYING WS-MSGINFO-I from 1 by 1 Until WS-MSGINFO-I > WS-MSGINFO-INDEX WRITE FILEREC FROM WS-MSGINFO-BLOCK-ENTRY (WS-MSGINFO-I) COMPUTE LPERPAGE-COUNT = LPERPAGE-COUNT + 1 END-PERFORM MOVE SPACES to FILEREC COMPUTE REC-SIZE = 1 WRITE FILEREC COMPUTE LPERPAGE-COUNT = LPERPAGE-COUNT + 1 . 9100-PRINT-FS-STATUS-EXIT. EXIT. 9150-PRINT-INPUT-SIZE. COMPUTE length-pointer = 1 MOVE SPACES to FILEREC MOVE WS-COUNT to WS-ZCOUNT STRING 'XMLQRY1I *** File ' WS-FNAME ', Records read: ' WS-ZCOUNT DELIMITED BY SIZE INTO DATA-FILEREC WITH POINTER length-pointer IF LPERPAGE-COUNT + 1 >= MAX-PER-PAGE MOVE 1 to ASA-FILEREC LPERPAGE-COUNT END-IF 86 Cobol, XML and XSD COMPUTE REC-SIZE= length-pointer WRITE FILEREC COMPUTE LPERPAGE-COUNT = LPERPAGE-COUNT + 1 MOVE SPACES to FILEREC MOVE QXD-Input-Buffer-Length to WS-ZCOUNT COMPUTE length-pointer = 1 STRING 'XMLQRY1I *** File ' WS-FNAME ', Bytes read: WS-ZCOUNT DELIMITED BY SIZE INTO DATA-FILEREC WITH POINTER length-pointer IF LPERPAGE-COUNT + 1 >= MAX-PER-PAGE MOVE 1 to ASA-FILEREC LPERPAGE-COUNT END-IF COMPUTE REC-SIZE= length-pointer WRITE FILEREC COMPUTE LPERPAGE-COUNT = LPERPAGE-COUNT + 1 . 9150-PRINT-INPUT-SIZE-EXIT. EXIT. / * ** Print the QXD input buffer by chunks of 132 bytes. 9200-PRINT-QXD-INPUT. ' Compute length-pointer = 1 STRING 'XMLQRY1I *** Input to the XML Parser follows:' DELIMITED BY SIZE INTO DATA-FILEREC WITH POINTER length-pointer IF LPERPAGE-COUNT + 1 >= MAX-PER-PAGE MOVE 1 to ASA-FILEREC LPERPAGE-COUNT END-IF COMPUTE REC-SIZE= length-pointer WRITE FILEREC COMPUTE LPERPAGE-COUNT = LPERPAGE-COUNT + 1 Perform 9050-PRINT-BLANK-LINE thru 9050-PRINT-BLANK-LINE-EXIT MOVE 1 to WS-POS MOVE 133 to REC-SIZE MOVE 0 to WS-COUNT PERFORM UNTIL WS-POS >= QXD-input-buffer-length MOVE SPACES to FILEREC * ** Honor the LPER value but don't print the header on each * ** page. 87 Cobol, XML and XSD IF LPERPAGE-COUNT + 1 >= MAX-PER-PAGE MOVE 1 to ASA-FILEREC LPERPAGE-COUNT ELSE MOVE SPACE to ASA-FILEREC END-IF * ** Move part of the QXD buffer to the print line. On the * ** last segment the number of characters to print is * ** len-pos +1. COMPUTE WS-LEN = QXD-input-buffer-length - WS-POS IF WS-LEN <= REC-SIZE - 1 COMPUTE REC-SIZE = WS-LEN + 2 END-IF MOVE QXD-Input-Buffer(WS-POS:REC-SIZE - 1) to DATA-FILEREC WRITE FILEREC COMPUTE LPERPAGE-COUNT = LPERPAGE-COUNT + 1 COMPUTE WS-POS = WS-POS + REC-SIZE - 1 END-PERFORM . 9200-PRINT-QXD-INPUT-EXIT. EXIT. / 9800-PRINT-ENDMSG. IF LPERPAGE-COUNT + 1 >= MAX-PER-PAGE MOVE 1 to ASA-FILEREC LPERPAGE-COUNT PERFORM 9000-PRINT-HEADER THRU 9000-PRINT-HEADER-EXIT ELSE MOVE SPACE to ASA-FILEREC END-IF MOVE SPACES to DATA-FILEREC WRITE FILEREC COMPUTE LPERPAGE-COUNT = LPERPAGE-COUNT + 1 MOVE SPACES to FILEREC MOVE 'XMLQRY1I *** End of XML text reached. ' TO DATA-FILEREC WRITE FILEREC COMPUTE LPERPAGE-COUNT = LPERPAGE-COUNT + 1 . 9800-PRINT-ENDMSG-EXIT. EXIT. ***************************************************************** * Subroutines. 8000-DATE-TIME * 88 Cobol, XML and XSD * 8100-GET-SYSID * ***************************************************************** 8000-DATE-TIME. ACCEPT WS-TIME FROM TIME ACCEPT WS-DATE-YYMMDD FROM DATE ACCEPT WS-DAY-YYDDD FROM DAY ACCEPT WS-DAY-OF-WEEK FROM DAY-OF-WEEK . 8000-DATE-TIME-EXIT. EXIT. 8100-GET-SYSID. SET Address of PSA to Null SET Address of CVT to flccvt SET Address of SMCA to cvtsmca * The MOVE below is necessary to actually access the SMCASID field * Before that the SMCASID field cannot be used directly. MOVE SMCASID to WS-SYSID . 8100-GET-SYSID-EXIT. EXIT. 89 Cobol, XML and XSD 2.2. The build of the module and its execution This program can be compiled using a standard compile and link job. The input of this job can be the XML source that XMLCOB1 program created. //useridX JOB accnt,'Run module',CLASS=A //GO EXEC PGM=XMLQRY1 //STEPLIB DD DISP=SHR,DSN=userid.XML.PDSELOAD //SYSPRINT DD SYSOUT=* //TSTXML DD DISP=SHR,DSN=userid.XML.SOURCE(TSTXML) //SYSPRINT DD SYSOUT=* //SYSIN DD DUMMY XMLQRY1 produces a report as shown below. XMLQRY1 Utility v1r0 System XXXX XMLQRY1I *** File SYSPRINT successfully opened. XMLQRY1I *** File TSTXML successfully opened. XMLQRY1I *** File TSTXML XMLQRY1I *** File TSTXML , Records read: , Bytes read: 35 572 XMLQRY1I *** Input to the XML Parser follows: <?xml version="1.0" encoding="ibm_1140"?><test_list><test_entry><individual_id>XYZ0 TTE</lastname><firstname>Patrice</firstname></individual_name><individual_a2><count redbooks_number></individual_a2></test_entry><test_entry><individual_id>02A546Z9</i astname><firstname>Andy</firstname></individual_name><individual_a2><country_code>D er></individual_a2></test_entry></test_list> XMLQRY1I *** XML Parser results follow: QXD version : 1 XML Autodet Value : 8 XML Autodet CCSID : 37 XML Version : 1 XML Release : 0 XML Spec CCSID : 1140 XML Flag 1 : . XML Flag 2 : XML Reserved : 0 XML Decl Length : 0 90 Chapter 3. C++ and XML This chapter goes one step further and deals with the interface between C++ programs and XML parsers. It is based on the examples that come with the XML toolkit for z/OS. There are three sets of examples further down referred as • The samples programs. These programs are examples of using the XML Parser, C++ Edition. • The zsamples programs. These programs deal with using Z/OS specific classes of the XML Parse, C ++ Edition. • The xslt programs call the Xalan transformer to produce new documents from xml documents. Reference The XML Toolkit for z/OS User's Guide Requirements • User has access to the TSO/E environment • User has access to the USS • The XML Toolkit is available. Its usual location is like /usr/lpp/ixm/IBM/xml4c-5_x • The Transformer part of the XML toolkit is installed in /usr/lpp/ixm/IBM/xslt4c-1_11 In the next pages we assume the tookit is installed in /usr/lpp/ixm/IBM/xml4c-5_7. It will also be assumed user has created a folder named /a/userid/xml The toolkit contains • The XML Parser, C++ Edition, which is based on the Xerces Apache Foundation open source • The XSLT Processor, C++ Edition, which is based on the Xalan Apache Foundation open source • In the xml4c folder, a 'samples' subfolder • In the xml4c folder, a 'zsamples' subfolder • In the xslt4c folder, a 'samples' subfolder The toolkit supports three modes of execution. • 31-bit support non-XPLINK • 31-bit support XPLINK • 64-bit support. There's no 64-bit support non-XPLINK XPLINK stands for Extra Performance Linkage. It is a special way of linking modules for better performances. 91 C++ and XML 1. Try the pre-installed IBM samples programs This section explains how to make sure the XML Toolkit is installed properly by running the pre-built IBM samples programs. IBM provides pre-built versions of each set of the samples, zsamples and xslt programs. We here only deal with running the first set of examples. Add and export these variables in your .profile or type the export commands to set up these variables in your current session. • export XERCESCROOT=/usr/lpp/ixm/IBM/xml4c-5_7 • export LIBPATH=$XERCESCROOT/lib:$LIBPATH • export PATH=$XERCESCROOT/bin:$PATH (31-bit modes) • export PATH=$XERCESCROOT/bin64:$PATH (64-bit mode) • export XERCESCOUT=/a/userid/xml Warning! Make sure you typed XERCESCROOT and XERCESCOUT with a 'C' following XERCES in both. Change your current directory and execute the DOMPrint sample • cd $XERCESCROOT/samples/data • DOMPrint -v=always -wenc=IBM-1047-s390 -wfpp=on personal.xml If the Toolkit is installed and the environment set as suggested DOMPrint will 'print' XML lines to the screen such as <person id="two.worker"> <name> <family>Worker</family> <given>Two</given> </name> <email>two@foo.com</email> <link manager="Big.Boss"/> </person> <person id="three.worker"> <name> <family>Worker</family> <given>Three</given> </name> <email>three@foo.com</email> <link manager="Big.Boss"/> </person> <person id="four.worker"> <name> <family>Worker</family> <given>Four</given> </name> 92 C++ and XML <email>four@foo.com</email> <link manager="Big.Boss"/> </person> The XML toolkit ships with these examples: C_Sample, CreateDOMDocument, DOMCount, DOMPrint, EnumVal, MemParse, PParse, PSVIWriter, Redirect, SAX2Count, SAX2Print, SAXCount, SAXPrint, SCMPrint, StdInParse. See the XML toolkit for Z/OS User's guide, chapter 5 for a description of each example. 93 C++ and XML 2. Generate and execute the samples in the USS In this section we generate all the examples in a private folder and create a script that helps in the execution of these many examples. The are five steps for building and executing these programs: • Get and install the GNU gmake utility • Prepare your environment • Configure and execute gmake • Script the build of the examples • Script the execution of the examples 94 C++ and XML 2.1. Get and install the GNU gmake utility If the gmake utility is not in the all-purpose /bin directory of the USS it may be necessary to install it. • Download the gmake.pax.Z.bin from this [http://www.ibm.com/servers/eserver/zseries/zos/unix/ bpxa1ty1.html#gmake] IBM page • Copy the bin file right in /a/userid • In /a/userid enter pax –rzf gmake.pax.Z.bin This will create the gmake utility in the /a/userid/bin folder • Export PATH=$XERCESCROOT/bin64:$PATH (64-bit mode) 95 C++ and XML 2.2. Prepare your environment Write authority is needed so it is likely you won't be able to (re)build the examples in the IBM installation directory. Use the cp command to copy the examples to your private area. In the below XERCESCROOT and XERCESCOUT are variables that contain the source and target locations and that you set up in the prior section. • cp -r $XERCESCROOT/samples $XERCESCOUT 96 C++ and XML 2.3. Configure and execute gmake Enter these exports, the unset and configure commands • export CXX=c++ • export CXXFLAGS="-2" ("-g" for debugging) • export OS390_BIT64=1 (64-bit run; don't set for 31-bit modes) • export OS390_XPLINK=1 (31-bit XPLINK mode) • export PATH=/a/userid/bin:/a/userid/xml/samples:$PATH • unset _CXX_CXXSUFFIX • configure The configure utility has created a Makefile for each sample Finally enter • gmake to let the utility search all the sub-folders in your /samples location and build all the executables. 97 C++ and XML 2.4. Script the build of the examples Alternatively you may create the script samples.bat in /a/userid/xml/samples that sets the variables and performs the commands listed in the prior section. • Create samples.bat using the below model. # # This script sets variables and executes the command that configure # and build the samples. # echo "* Setting variables" unset _CXX_CXXSUFFIX export CXX=c++ export CXXFLAGS="-2" # # OS390_XPLINK=1 if building the 31-bit XPLINK samples # OS390_BIT64=1 the 64-bit samples export OS390_BIT64=1 # # Just in case set XERCESCROOT path - it contains the version.incl # file for gmake; set the XERCES output location. Make the samples # directory the current directory. # export XERCESCROOT=/usr/lpp/ixm/IBM/xml4c-5_7 export XERCESCOUT=/a/userid/xml echo "* Changing current directory " cd $XERCESCOUT/samples # # Run the configure script (must be in the path) # echo "* Execute configure " configure # # Export variables for gmake # export _CXX_CXXSUFFIX=cpp export _CXX_CCMODE=1 # # Run gmake # echo "* Execute gmake" gmake # ## ### End of script • Run samples.bat The script prepares the environment and builds all the executables. 98 C++ and XML 2.5. Script the execution of the examples Create in the /samples folder the xsamples.bat script that facilitate the execution of the examples • Create xsamples.bat using the below model. # # # # # # # # passing arguments to a shell script $* $@ $0 $n $# if test then echo echo echo echo echo echo echo echo echo echo echo echo echo echo echo echo echo echo echo echo echo echo echo echo echo echo echo echo echo echo echo echo echo echo echo echo = = = = = the the the the the complete string passed to the script sequence of strings the argument is made of script name nth string number of strings passed to the script. "$1" = "" ' ' '============================================ ' ' ' ' XML Toolkit for z/OS ' ' ' 'Usage: ' ' xsamples.bat executes the application ' 'whose name is passed as an argument. ' ' ' 'The program must be available in the path. ' ' ' 'Each application processes the same xml ' 'input: ' ' ' $XERCESCROOT/samples/data/personal.xml '============================================ ' ' ' 'The following applications are available: ' ' ' 'C_Sample $XERCESCROOT/samples/data/personal.xml ' ' An example of a C program that calls the XML ' ' parser, C++ edition ' ' ' 'CreateDOMDocument (no parameter) ' ' This program creates a new DOM document from scratch ' in memory. ' It then prints the count of elements in the tree. ' 'DOMCount -p $XERCESCROOT/samples/data/personal.xml ' Counts the elements, attributes, spaces and ' ' characters in an XML file ' ' ' ' use option -p for print ' ' use option -v=always to trigger the validation ' ' ' 'DOMPrint $XERCESCROOT/samples/data/personal.xml ' 99 ' ' ' ' ' C++ and XML echo ' Parses the xml input file, then calls DOMWrite ' echo ' to print the elements. ' echo ' ' echo 'EnumVal $XERCESCROOT/samples/data/personal.xml ' echo ' Enumerates the markup declarations in a DTD file (?)' echo ' ' echo 'MemParse -v=always ' echo ' This program uses the SAX Parser to parse a memory ' echo ' buffer containing XML statements, and reports the number' echo ' of elements and attributes found. ' echo ' ' echo 'PParse -v=always $XERCESCROOT/samples/data/personal.xml' echo ' Progressive parsing ' echo ' ' echo 'PSVIWriter ' echo ' ?? ' echo ' ' echo 'Redirect $XERCESCROOT/samples/data/personal.xml ' echo ' Redirect the input stream for external entities. ' echo ' ' echo ' !! Current directory must contain direct.dtd !! ' echo ' ' echo 'SAX2Count $XERCESCROOT/samples/data/personal.xml ' echo ' Counts the elements, attributes, spaces and characters ' echo ' in an XML file ' echo ' ' echo 'SAX2Print $XERCESCROOT/samples/data/personal.xml ' echo ' Parses an XML file and prints it out. ' echo ' ' echo 'SAXCount $XERCESCROOT/samples/data/personal.xml ' echo ' Counts the elements, attributes, spaces and characters ' echo ' in an XML file ' echo ' ' echo 'SAXPrint $XERCESCROOT/samples/data/personal.xml ' echo ' Parses an XML file and prints it out. ' echo ' ' echo 'SCMPrint $XERCESCROOT/samples/data/personal.xsd ' echo ' This program parses XML Schema file(s), to show how one can echo ' access the Schema Content Model information. echo ' ' echo 'SEnumVal $XERCESCROOT/samples/data/personal-schema.xml' echo ' Enumerates the markup declarations in a schema ' echo ' file ' echo ' ' echo 'StdInParse -v=always <$XERCESCROOT/samples/data/personal.xsd echo ' streaming XML data from standard input echo ' ' echo ' !! Current directory must contain personal.dtd !!' echo ' ' elif test "$1" = "CreateDOMDocument" then if test "$2" != "" then echo '***' 100 ' ' ' ' C++ and XML echo '*** CreateDOMDocument doee not accept any parameter' echo '***' fi CreateDOMDocument # # Cannot continue the if test on several lines! # elif test "$1" = "C_Sample" -o "$1" = "DOMCount" -o "$1" = "DOMPrint" then echo '***' echo '*** xsamples.bat is starting the execution of '$1 echo '***' $1 $XERCESCROOT/samples/data/personal.xml echo echo echo elif test then echo echo echo '***' '*** Program has ended an returned control to xsamples.bat' '***' "$1" = "EnumVal" -o "$1" = "PParse" -o "$1" = "SAXCount" '***' '*** xsamples.bat is starting the execution of '$1 '***' $1 $XERCESCROOT/samples/data/personal.xml echo echo echo elif test then echo echo echo '***' '*** Program has ended an returned control to xsamples.bat' '***' "$1" = "SAXPrint" -o "$1" = "SAX2Count" -o "$1" = "SAX2Print" '***' '*** xsamples.bat is starting the execution of '$1 '***' $1 $XERCESCROOT/samples/data/personal.xml echo echo echo elif test then echo echo echo '***' '*** Program has ended an returned control to xsamples.bat' '***' "$1" = "MemParse" $1 '***' '*** xsamples.bat is starting the execution of '$1 '***' echo echo echo elif test then echo -v=always '***' '*** Program has ended an returned control to xsamples.bat' '***' "$1" = "Redirect" '***' 101 C++ and XML echo echo echo echo cd $1 '*** xsamples.bat is starting the execution of '$1 '***' '*** >>> Current directory now ' $XERCESCROOT/samples/data '***' echo echo echo elif test then echo echo echo $XERCESCROOT/samples/data $XERCESCROOT/samples/data/personal.xml '***' '*** Program has ended an returned control to xsamples.bat' '***' "$1" = "SCMPrint" $1 '***' '*** xsamples.bat is starting the execution of '$1 '***' echo echo echo elif test then echo echo echo $XERCESCROOT/samples/data/personal.xsd '***' '*** Program has ended an returned control to xsamples.bat' '***' "$1" = "SEnumVal" $1 '***' '*** xsamples.bat is starting the execution of '$1 '***' echo echo echo elif test then echo echo echo echo echo $XERCESCROOT/samples/data/personal-schema.xml cd $1 '***' '*** Program has ended an returned control to xsamples.bat' '***' "$1" = "StdInParse" '***' '*** xsamples.bat is starting the execution of '$1 '***' '*** >>> Current directory now ' $XERCESCROOT/samples/data '***' $XERCESCROOT/samples/data -v=always <$XERCESCROOT/samples/data/personal.xml echo '***' echo '*** Program has ended an returned control to xsamples.bat' echo '***' else echo '*** ' echo '*** Program name not recognized:' $1 echo '*** ' fi 102 C++ and XML • Run xsamples.bat • With no parameter xsamples.bat displays a help that gives the syntax for each program • To execute a given program run xsamples.bat passing the name of this program and parameters as expected by the program, for example xsamples.bat SAX2Print $XERCESCROOT/samples/data/personal.xml 103 C++ and XML 3. Generate in the USS to a Z/OS load library and execute in Z/OS The steps for building and executing the programs in Z/OS are at a high level the same steps we followed in the USS. • Install gmake • Prepare your environment • Prepare a script that configures your environment in the USS • Prepare a script that executes the gmake utility • Execute the scripts and the resulting loadmodules in a Z/OS job 104 C++ and XML 3.1. Install gmake See section "Get and Install the GNU make utility" 105 C++ and XML 3.2. Prepare your environment The same settings that were used in the USS apply. Additional settings are required to route the generated modules to a Z/OS library. • export LOADMOD=userid.SAMPLES.REL.LOAD • export LOADEXP=hlq.SIXMEXP LOADMOD can be given any name. It must be a PDSE (Library) with at least 500 tracks, RECFM=U, BLKSIZE=32760, LRECL=0 LOADEXP is the name of the Z/OS library that contains the toolkit. There is actually a set of libraries whose last qualifier is like SIXM*** 106 C++ and XML 3.3. Prepare the Configure script We create a script that we can later execute in a Z/OS batch job. • Create the zos-configure script in /a/userid/xml/samples cd /a/userid/xml/samples echo echo 'Set variables for XML processing - similar to the USS setup' echo export XERCESCROOT=/usr/lpp/ixm/IBM/xml4c-5_7 export XERCESCOUT=/a/userid/xml export XSLTROOT=/usr/lpp/ixm/IBM/xslt4c-1_11 export OS390BATCH=1 export OS390_BIT64=1 unset _CXX_SUFFIX export CXX=c++ export CXXFLAGS="-2" echo '** XMLROOT =' $XMLROOT echo '** XERCESCROOT =' $XERCESCROOT echo '** XERCESCOUT =' $XERCESCOUT echo '** XSLTROOT =' $XSLTROOT echo '** OS390BATCH =' $OS390BATCH echo '** CXX =' $CXX echo '** CXXFLAGS =' $CXXFLAGS echo '** OS390_BIT64 =' $OS390_BIT64 echo echo 'Set additional variables for z/OS processing' echo export LOADMOD=userid.SAMPLES.REL.LOAD export LOADEXP=hlq.SIXMEXP echo '** LOADMOD =' $LOADMOD echo '** LOADEXP =' $LOADEXP echo echo 'Running the configure script' echo configure 107 C++ and XML 3.4. Prepare a gmake script This script will be executed in a Z/OS batch job. • Create the zos-gmake script in /a/userid/xml/samples cd /a/userid/xml/samples echo echo 'Set variables for XML processing - similar to the USS setup' echo export XERCESCROOT=/usr/lpp/ixm/IBM/xml4c-5_7 export XERCESCOUT=/a/userid/xml export XSLTROOT=/usr/lpp/ixm/IBM/xslt4c-1_11 export OS390_BIT64=1 unset _CXX_SUFFIX export CXX=c++ export CXXFLAGS="-2" export CXX_SUFFIX=cpp export _CXX_CCMODE=1 echo '** XMLROOT =' $XMLROOT echo '** XERCESCROOT =' $XERCESCROOT echo '** XERCESCOUT =' $XERCESCOUT echo '** CXX =' $CXX echo '** CXXFLAGS =' $CXXFLAGS echo '** CXX_SUFFIX =' $CXX_SUFFIX echo '** _CXX_CCMODE =' $_CXX_CCMODE echo '** OS390_BIT64 =' $OS390_BIT64 echo echo 'Set additional variables for z/OS processing' echo export LOADMOD=userid.SAMPLES.REL.LOAD export LOADEXP=hlq.SIXMEXP export _CXX_XSUFFIX_HOST=SIXMEXP export OS390BATCH=1 echo '** LOADMOD =' $LOADMOD echo '** LOADEXP =' $LOADEXP echo '** _CXX_XSUFFIX_HOST = ' $_CXX_XSUFFIX_HOST echo echo 'Running gmake ' echo gmake 108 C++ and XML 3.5. Execute the scripts and loadmodules in a Z/OS batch job Copy this JCL to your JCL library and customize to your needs. This JCL contains conditional statements that can be set so that one or several steps are selected for execution. Each step executes depending on the value of its associated RUNnn variable. For example the execution of the RUN06 step depends on the RUN06 variable contents. See the comments in the JCL about setting the variables. Additionally, should a particular step terminate with a return code bigger than 4, all the steps that follow are automatically flushed. In its entirety this job • Creates a PDSE load library • Executes the script zos-configure in the USS • Executes the script zos-gmake in the USS • Executes each of the generated modules, eacn in its own step. //useridU JOB accnt,'BPXBATCH',CLASS=A //* //* ----------------------------------------------------------------//* This job requests UNIX SERVICES to setup the examples that //* ship with XML toolkit for z/OS. //* //* About the running a USS oriented job //* UNIX SYSTEMS SERVICES USER'S GUIDE (BPXA409) , CHAPTER 11 //* //* Strangely enough BPXBATCH does not support a STDIN Z/OS file //* and the STDPARM can be used to pass one line command in place of //* the exec parm. //* //* The DOCONF and DOGEN steps thus read pre-existing STDINs in //* the USS. //* //* HFS is case sensitive - use Caps on //* ----------------------------------------------------------------//* Building and executing the XML toolkit examples in z/OS //* 1. It is assumed the XML Toolkit exists in the USS and the //* examples have been copied to a private location. //* 2. The gmake utility exists or has been installed as explained //* in the manual XML ToolKit for z/OS User Guide, chapter 5, //* How to use the XML Parser C++ Edition //* //* This job //* //* 1. (Re-)allocate a PDSE load library, 500 tracks at least //* 2. Configure the private location prior to the generation //* 3. Generate the executables 109 C++ and XML //* 4. Execute each example //* ----------------------------------------------------------------//* The below SET statements drive the job execution or re-execution //* at step level //* The 'RC < 5' string ensures this step will execute only if any //* prior step executed with a RC not bigger than 4 //* The 'RC > 20'string ensures this step will NOT execute after //* prior steps all returned a RC in the range 0-20, //* so basically this step should always be skipped. //* ----------------------------------------------------------------//* // SET CREPDSE='RC < 5' // SET DOCONF='RC < 5' // SET DOGEN='RC < 5' // SET RUN01='RC > 20' CRDOMDOC // SET RUN02='RC > 20' CSAX2CNT // SET RUN03='RC < 5' DOMCOUNT // SET RUN04='RC < 5' DOMPRINT // SET RUN05='RC > 20' ENUMVAL // SET RUN06='RC < 5' MEMPARSE // SET RUN07='RC > 20' PPARSE // SET RUN08='RC > 20' PSVIWRIT // SET RUN09='RC > 20' REDIRECT // SET RUN10='RC < 5' SAXCOUNT // SET RUN11='RC < 5' SAXPRINT // SET RUN12='RC < 5' SAX2CONT // SET RUN13='RC < 5' SAX2PRNT // SET RUN14='RC > 20' SCMPRINT // SET RUN15='RC > 20' SENUMVAL // SET RUN16='RC > 20' STDINPAR // SET STEPLIB=userid.SAMPLES.REL.LOAD // SET IXMLOAD=hlq.SIXMLOD1 //* //* ----------------------------------------------------------------//* - Set MAXCC as appropriate to select the CREPDSE step on RC //* ----------------------------------------------------------------//SETRC EXEC PGM=IDCAMS //SYSPRINT DD SYSOUT=* //SYSIN DD * SET MAXCC=0 /* //* ----------------------------------------------------------------//* - Create PSDE load library //* ----------------------------------------------------------------// IF (&CREPDSE) THEN //CREPDSE EXEC PGM=IDCAMS //SYSPRINT DD SYSOUT=* //SYSIN DD * DELETE userid.SAMPLES.REL.LOAD SET MAXCC=00 /* */ ALLOC DA('userid.SAMPLES.REL.LOAD') + STORCLAS(TSO) DIR(0) DSORG(PO) + LRECL(0) RECFM(U) BLKSIZE(32760) + 110 C++ and XML DSNTYPE(LIBRARY) SPACE (500,50) TRACKS CATALOG + + /* // ENDIF //* ----------------------------------------------------------------//* - Run the configure script //* ----------------------------------------------------------------// IF (&DOCONF) THEN //RUNCONF EXEC PGM=BPXBATCH //STDENV DD * LOGNAME=userid HOME=/a/userid _BPX_BATCH_SPAWN=YES _BPX_SHAREAS=NO _BPX_SPAWN_SCRIPT=YES /* //STDPARM DD DUMMY //STDIN DD PATH='/a/userid/xml/samples/zos-configure', // PATHOPTS=(ORDONLY) //*TDOUT DD PATH='/a/userid/xml/samples/zos-runconf.out', //* PATHOPTS=(OWRONLY,OCREAT),PATHMODE=SIRWXU //*TDERR DD PATH='/a/userid/xml/samples/zos-runconf.err', //* PATHOPTS=(OWRONLY,OCREAT),PATHMODE=SIRWXU //* //* Alternative outputs //STDOUT DD SYSOUT=* //STDERR DD SYSOUT=* //SYSPRINT DD SYSOUT=* // ENDIF //* ----------------------------------------------------------------//* - Generate the the executables (gmake) //* ----------------------------------------------------------------// IF (&DOGEN) THEN //GMAKE EXEC PGM=BPXBATCH //STDENV DD * LOGNAME=userid HOME=/a/userid _BPX_BATCH_SPAWN=YES _BPX_SHAREAS=NO _BPX_SPAWN_SCRIPT=YES //STDPARM DD DUMMY //STDIN DD PATH='/a/userid/xml/samples/zos-gmake', // PATHOPTS=(ORDONLY) //STDOUT DD SYSOUT=* //STDERR DD SYSOUT=* //*TDOUT DD PATH='/a/userid/xml/samples/zos-gmake.out', //* PATHOPTS=(OWRONLY,OCREAT),PATHMODE=SIRWXU //*TDERR DD PATH='/a/userid/xml/samples/zos-gmake.err', //* PATHOPTS=(OWRONLY,OCREAT),PATHMODE=SIRWXU //SYSPRINT DD SYSOUT=* //* /* // ENDIF 111 C++ and XML //* ----------------------------------------------------------------//* - Run the example #1 //* ----------------------------------------------------------------// IF (&RUN01) THEN //RUN01 EXEC PGM=CRDOMDOC, // PARM=('///usr/lpp/ixm/IBM/xml4c-5_7/samples/data/personal.xml') //* //* Alternative syntaxes can be used to allocate a z/os file input //* //* PARM='///DD:XMLDATA(PERSONAL)' //* PARM='DD:XMLDATA(PERSONAL)' //* //* PARM='"//''userid.XML.DATA(PERSONAL)''"' //* PARM='"//XML.DATA(PERSONAL)"' (automatic prefixation) //* //STEPLIB DD DISP=SHR,DSN=&STEPLIB // DD DISP=SHR,DSN=&IXMLOAD //*XMLDATA DD DISP=SHR,DSN=userid.XML.DATA // ENDIF //* ----------------------------------------------------------------//* - Run the example #2 //* ----------------------------------------------------------------// IF (&RUN02) THEN //RUN02 EXEC PGM=CSAX2CNT, // PARM=('///usr/lpp/ixm/IBM/xml4c-5_7/samples/data/personal.xml') //STEPLIB DD DISP=SHR,DSN=&STEPLIB // DD DISP=SHR,DSN=&IXMLOAD // ENDIF //* ----------------------------------------------------------------//* - Run the example #3 //* ----------------------------------------------------------------// IF (&RUN03) THEN //RUN03 EXEC PGM=DOMCOUNT, // PARM=('///usr/lpp/ixm/IBM/xml4c-5_7/samples/data/personal.xml') //STEPLIB DD DISP=SHR,DSN=&STEPLIB // DD DISP=SHR,DSN=&IXMLOAD // ENDIF //* ----------------------------------------------------------------//* - Run the example #4 //* ----------------------------------------------------------------// IF (&RUN04) THEN //RUN04 EXEC PGM=DOMPRINT, // PARM=('///usr/lpp/ixm/IBM/xml4c-5_7/samples/data/personal.xml') //STEPLIB DD DISP=SHR,DSN=&STEPLIB // DD DISP=SHR,DSN=&IXMLOAD // ENDIF //* ----------------------------------------------------------------//* - Run the example #5 //* ----------------------------------------------------------------// IF (&RUN05) THEN //RUN05 EXEC PGM=ENUMVAL, // PARM=('///usr/lpp/ixm/IBM/xml4c-5_7/samples/data/personal.xml') //STEPLIB DD DISP=SHR,DSN=&STEPLIB // DD DISP=SHR,DSN=&IXMLOAD 112 C++ and XML // ENDIF //* ----------------------------------------------------------------//* - Run the example #6 //* ----------------------------------------------------------------// IF (&RUN06) THEN //RUN06 EXEC PGM=MEMPARSE, // PARM=('-v=always') //STEPLIB DD DISP=SHR,DSN=&STEPLIB // DD DISP=SHR,DSN=&IXMLOAD // ENDIF //* ----------------------------------------------------------------//* - Run the example #7 //* ----------------------------------------------------------------// IF (&RUN07) THEN //RUN07 EXEC PGM=PPARSE, // PARM=('///usr/lpp/ixm/IBM/xml4c-5_7/samples/data/personal.xml') //STEPLIB DD DISP=SHR,DSN=&STEPLIB // DD DISP=SHR,DSN=&IXMLOAD // ENDIF //* ----------------------------------------------------------------//* - Run the example #8 //* ----------------------------------------------------------------// IF (&RUN08) THEN //RUN08 EXEC PGM=PSVIWRIT, // PARM=('////usr/lpp/ixm/IBM/xml4c-5_7/samples/data/personal.xml') //STEPLIB DD DISP=SHR,DSN=&STEPLIB // DD DISP=SHR,DSN=&IXMLOAD // ENDIF //* ----------------------------------------------------------------//* - Run the example #9 //* ----------------------------------------------------------------// IF (&RUN09) THEN //RUN09 EXEC PGM=REDIRECT, // PARM=('///usr/lpp/ixm/IBM/xml4c-5_7/samples/data/personal.xml') //STEPLIB DD DISP=SHR,DSN=&STEPLIB // DD DISP=SHR,DSN=&IXMLOAD // ENDIF //* ----------------------------------------------------------------//* - Run the example #10 //* ----------------------------------------------------------------// IF (&RUN10) THEN //RUN10 EXEC PGM=SAXCOUNT, // PARM=('///usr/lpp/ixm/IBM/xml4c-5_7/samples/data/personal.xml') //STEPLIB DD DISP=SHR,DSN=&STEPLIB // DD DISP=SHR,DSN=&IXMLOAD // ENDIF //* ----------------------------------------------------------------//* - Run the example #11 //* ----------------------------------------------------------------// IF (&RUN11) THEN //RUN11 EXEC PGM=SAXPRINT, // PARM=('///usr/lpp/ixm/IBM/xml4c-5_7/samples/data/personal.xml') //STEPLIB DD DISP=SHR,DSN=&STEPLIB // DD DISP=SHR,DSN=&IXMLOAD 113 C++ and XML // ENDIF //* ----------------------------------------------------------------//* - Run the example #12 //* ----------------------------------------------------------------// IF (&RUN12) THEN //RUN12 EXEC PGM=SAX2CONT, // PARM=('///usr/lpp/ixm/IBM/xml4c-5_7/samples/data/personal.xml') //STEPLIB DD DISP=SHR,DSN=&STEPLIB // DD DISP=SHR,DSN=&IXMLOAD // ENDIF //* ----------------------------------------------------------------//* - Run the example #13 //* ----------------------------------------------------------------// IF (&RUN13) THEN //RUN13 EXEC PGM=SAX2PRNT, // PARM=('///usr/lpp/ixm/IBM/xml4c-5_7/samples/data/personal.xml') //STEPLIB DD DISP=SHR,DSN=&STEPLIB // DD DISP=SHR,DSN=&IXMLOAD // ENDIF //* ----------------------------------------------------------------//* - Run the example #14 //* ----------------------------------------------------------------// IF (&RUN14) THEN //RUN14 EXEC PGM=SCMPRINT, // PARM=('///usr/lpp/ixm/IBM/xml4c-5_7/samples/data/personal.xml') //STEPLIB DD DISP=SHR,DSN=&STEPLIB // DD DISP=SHR,DSN=&IXMLOAD // ENDIF //* ----------------------------------------------------------------//* - Run the example #15 //* ----------------------------------------------------------------// IF (&RUN15) THEN //RUN15 EXEC PGM=SENUMVAL, // PARM=('///usr/lpp/ixm/IBM/xml4c-5_7/samples/data/personal.xml') //STEPLIB DD DISP=SHR,DSN=&STEPLIB // DD DISP=SHR,DSN=&IXMLOAD // ENDIF //* ----------------------------------------------------------------//* - Run the example #16 //* ----------------------------------------------------------------// IF (&RUN16) THEN //RUN16 EXEC PGM=STDINPAR, // PARM=('///usr/lpp/ixm/IBM/xml4c-5_7/samples/data/personal.xml') //STEPLIB DD DISP=SHR,DSN=&STEPLIB // DD DISP=SHR,DSN=&IXMLOAD // ENDIF 114 C++ and XML 4. Fully generate an example in Z/OS In the prior section the build of the Z/OS load modules was performed in the USS. In this section we see how an application can be entirely generated in a Z/OS batch job. Consider the SAX2Count example that can be found in the USS. It is made of the following: • The SAX2Count.cpp source • The SAX2Count.hpp include • The SAX2CountHandlers.cpp source • The SAX2CountHandlers.hpp include These sources will be copied to a Z/OS library and processed in Z/OS to generate and execute the SAX2COUNT application in Z/OS. Allocate PDSE data sets as detailed below • userid.BATCH.CPP recfm=FB, lrecl=240, blksize=12960 • userid.BATCH.HPP recfm=FB, lrecl=240, blksize=12960 • userid.BATCH.JCL recfm=FB, lrecl=80, blksize=12960 • userid.BATCH.OBJ recfm=FB, lrecl=80, blksize=12960 • userid.BATCH.LOAD recfm=U, lrecl=0, blksize=32760 • userid.BATCH.XML recfm=FB, lrecl=80, blksize=12960 Copy and edit as follows • Copy SAX2Count.cpp and SAX2CountHandlers.cpp as SAX2CNT and SAX2HND members to the CPP library cp SAX2Count.cpp "//'userid.BATCH.CPP(SAX2CNT)'" cp SAX2CountHandlers.cpp "//'userid.BATCH.CPP(SAX2HND)'" • Copy SAX2Count.hpp and SAX2CountHandlers.hpp as SAX2CNTH and SAX2HNDH members to the HPP library cp SAX2Count.hpp "//'userid.BATCH.HPP(SAX2CNTH)'" cp SAX2CountHandlers.hpp "//'userid.BATCH.HPP(SAX2HNDH)'" 115 C++ and XML • Edit SAX2CNT member and change in the #include "SAXCountHandlers.hpp" to "SAXConth.hpp" // -----------------------------------------------------// Includes // -----------------------------------------------------#include "SAX2CNTH.hpp" #include <xercesc/util/PlatformUtils.hpp> #include <xercesc/sax2/SAX2XMLReader.hpp> #include <xercesc/sax2/XMLReaderFactory.hpp> #if defined(XERCES_NEW_IOSTREAMS) #include <fstream> #else #include <fstream.h> #endif #include <xercesc/util/OutOfMemoryException.hpp> • Edit SAX2HND member and modify the #include as shown // -------------------------------------------// Includes // -------------------------------------------#include "SAX2CNTH.hpp" #include <xercesc/sax2/Attributes.hpp> #include <xercesc/sax/SAXParseException.hpp> #include <xercesc/sax/SAXException.hpp> • Last, edit SAX2HNDH member and modify the #include as shown // --------------------------------------------------// Includes for all the program files to see // --------------------------------------------------#include <xercesc/util/PlatformUtils.hpp> #include <stdlib.h> #include <string.h> #if defined(XERCES_NEW_IOSTREAMS) #include <iostream> #else #include <iostream.h> #endif #include "SAX2HNDH.hpp" #include <xercesc/sax2/XMLReaderFactory.hpp> #include <xercesc/sax2/SAX2XMLReader.hpp> Create member XMLCPPJ in the JCL library and submit 116 C++ and XML //useridX JOB accnt,'Gen and run',CLASS=A //* // SET MODULE=SAX2CNT // SET IXMLOAD=hqual.SIXMLOD1 //* //JOBLIB DD DISP=SHR,DSN=CEE.SCEERUN // DD DISP=SHR,DSN=CEE.SCEERUN2 // DD DISP=SHR,DSN=CBC.SCCNCMP //* //* --------------------------------------------------------------//* CPPPROC procedure invokes the CPP compiler //* --------------------------------------------------------------//CPPPROC PROC MEMBER=, // SRCLIB= //COMPILE EXEC PGM=CCNDRVR,PARM='/CXX OPTFILE(DD:OPTS),OBJ,LIST' //SYSLIN DD DISP=SHR,DSN=&SYSUID..BATCH.OBJ(&MEMBER) //SYSPRINT DD SYSOUT=A //SYSIN DD DISP=SHR,DSN=&SRCLIB(&MEMBER) //SYSUT1 DD DUMMY //OPTS DD DUMMY // PEND //* --------------------------------------------------------------//* CPPLINK procedure invokes the linker in a CPP context //* --------------------------------------------------------------//CPPLINK PROC //LINK EXEC PGM=IEWL,PARM='OPTIONS=OPTS' //SYSLIB DD DISP=SHR,DSN=CEE.SCEELKEX // DD DISP=SHR,DSN=CEE.SCEELKED // DD DISP=SHR,DSN=CEE.SCEECPP // DD DISP=SHR,DSN=CBC.SCLBSID //SYSLIB1 DD DISP=SHR, // DSN=hqual.SIXMEXP //SYSLIB2 DD DISP=SHR,DSN=&SYSUID..BATCH.OBJ //SYSLMOD DD DISP=SHR,DSN=&SYSUID..BATCH.LOAD //SYSDEFSD DD DUMMY //SYSPRINT DD SYSOUT=A //SYSDEFSD DD DUMMY //OPTS DD DUMMY //SYSLIN DD DUMMY // PEND //* //* Compile SAX2CNT //* //COMPILE EXEC PROC=CPPPROC, // MEMBER=SAX2CNT, // SRCLIB=&SYSUID..BATCH.CPP //OPTS DD * LANGLVL(EXTENDED) NOSEARCH SEARCH( /usr/lpp/ixm/IBM/xml4c-5_7/include/, //'userid.BATCH.+', //'CEE.SCEEH.+', //'CBC.SCLBH.+') 117 C++ and XML DEFINE(OS390=1) DEFINE(_OPEN_THREADS=1) DEFINE(_XOPEN_SOURCE_EXTENDED=1) /* //* //* Compile SAX2HND //* //COMPILE EXEC PROC=CPPPROC, // MEMBER=SAX2HND, // SRCLIB=&SYSUID..BATCH.CPP //OPTS DD * LANGLVL(EXTENDED) NOSEARCH SEARCH( /usr/lpp/ixm/IBM/xml4c-5_7/include/, //'userid.BATCH.+', //'CEE.SCEEH.+', //'CBC.SCLBH.+') DEFINE(OS390=1) DEFINE(_OPEN_THREADS=1) DEFINE(_XOPEN_SOURCE_EXTENDED=1) /* //* //* Compile SAX2CNTH //* //COMPILE EXEC PROC=CPPPROC, // MEMBER=SAX2CNTH, // SRCLIB=&SYSUID..BATCH.HPP //OPTS DD * LANGLVL(EXTENDED) NOSEARCH SEARCH( /usr/lpp/ixm/IBM/xml4c-5_7/include/, //'userid.BATCH.+', //'CEE.SCEEH.+', //'CBC.SCLBH.+') DEFINE(OS390=1) DEFINE(_OPEN_THREADS=1) DEFINE(_XOPEN_SOURCE_EXTENDED=1) /* //* //* Compile SAX2HNDH //* //COMPILE EXEC PROC=CPPPROC, // MEMBER=SAX2HNDH, // SRCLIB=&SYSUID..BATCH.HPP //OPTS DD * LANGLVL(EXTENDED) NOSEARCH SEARCH( /usr/lpp/ixm/IBM/xml4c-5_7/include/, //'userid.BATCH.+', //'CEE.SCEEH.+', //'CBC.SCLBH.+') DEFINE(OS390=1) DEFINE(_OPEN_THREADS=1) DEFINE(_XOPEN_SOURCE_EXTENDED=1) 118 C++ and XML /* //* //* Build the module //* //LINK EXEC PROC=CPPLINK //OPTS DD * AMODE=31,RMODE=ANY DYNAM=DLL,ALIASES=NO,UPCASE=NO LIST=NO,MAP=NO,XREF=NO, REUS=RENT,EDIT=YES,AC=0,CALL=YES,CASE=MIXED /* //SYSLIN DD * INCLUDE SYSLIB(IOSTREAM) INCLUDE SYSLIB(COMPLEX) INCLUDE SYSLIB1(IXM4C57X) INCLUDE SYSLIB2(SAX2CNT) INCLUDE SYSLIB2(SAX2HND) INCLUDE SYSLIB2(SAX2CNTH) INCLUDE SYSLIB2(SAX2HNDH) ENTRY CEESTART NAME SAX2CNT(R) RC=0 /* //* //* Execute the module //* //GO EXEC PGM=&MODULE, // PARM=('////usr/lpp/ixm/IBM/xml4c-5_7/samples/data/pe // rsonal.xml') //STEPLIB DD DISP=SHR,DSN=&SYSUID..BATCH.LOAD // DD DISP=SHR,DSN=&IXMLOAD The SAX2CNT module should execute with a return code of 0 and produce this single line ********************************* Top of Data ********************************* /samples/data/personal.xml: 46 ms (37 elems, 12 attrs, 134 spaces, 134 chars) ******************************** Bottom of Data ******************************* Note Even with the sources in Z/OS libraries the build still needs to include elements that are stored in the USS. See the OPTS contents in the Compilations. Note also the input data can reside in the USS. 119 C++ and XML 5. How to use the z/OS specific parser classes The XML Toolkit for z/OS brings z/OS specific parser classes that can be used in place of the regular Xerces classes. These examples can be found in the zsamples subfolder of the toolkit: zDOMCount, zDOMPrint, zDOMPParse, zMemParse, zSAX2Count and zSAX2Print. The z/OS specific classes all start with the letter 'z'. For example zSAX2XMLReader class. This section covers these topics: • Generate zsamples in the USS • Execute in the USS • Generate zsamples in Z/OS • Execute zsamples in Z/OS 120 C++ and XML 5.1. Generate zsamples If you generated the samples set of examples, not much is needed to generate that second set but adjusting the input and output locations. • Copy the zsamples programs to your private area cp -r $XERCESCROOT/zsamples $XERCESCOUT • Add the zsamples folder to your path: export PATH=/a/userid/xml/zsamples:$PATH • Create zsamples.bat in /a/userid/xml/zsamples by copying samples.bat and change the cd command: echo cd "* Changing current directory " $XERCESCOUT/zsamples • Run zsamples.bat Notes • We copied the entire zsamples folder to our private zsamples area. In addition to the sources the zsamples folder contains Makefiles and other files that are necessary for the generation. Copying only the sources and executing the script would fail to generate the modules. • The modules are stored in /a/userid/bin 121 C++ and XML 5.2. Execute zsamples in the USS Adjust your path to include the zsamples folder. Then the modules can be executed individually. For example: zMemParse -v=never A script such as the below one can be created to facilitate the testing of the examples # # # # # # # # passing arguments to a shell script $* $@ $0 $n $# = = = = = the the the the the complete string passed to the script sequence of strings the argument is made of script name nth string number of strings passed to the script. if test "$1" = "" then echo ' ' echo '============================================ ' echo ' ' echo ' XML Toolkit for z/OS ' echo ' ' echo 'Usage: ' echo ' xsamples.bat executes the application ' echo 'whose name is passed as an argument. ' echo ' ' echo 'The program must be available in the path. ' echo ' ' echo 'Each application processes the same xml ' echo 'input: ' echo ' ' echo $XERCESCROOT/samples/data/personal.xml echo '============================================ ' echo ' ' echo 'The following applications are available: ' echo ' ' echo 'zDOMCount -p $XERCESCROOT/samples/data/personal.xml echo ' Counts the elements, attributes, spaces and ' echo ' characters in an XML file ' echo ' ' echo ' use option -p for print ' echo ' use option -v=always to trigger the validation ' echo ' ' echo 'ZDOMPrint $XERCESCROOT/samples/data/personal.xml ' echo ' Parses the xml input file, then calls DOMWrite echo ' to print the elements. ' echo ' ' 122 ' ' C++ and XML echo echo echo echo echo echo echo echo echo echo echo echo echo echo echo echo echo echo 'ZDOMPParse $XERCESCROOT/samples/data/personal.xml ' ' ' 'zMemParse -v=always ' ' This program uses the SAX Parser to parse a memory ' ' buffer containing XML statements, and reports the number' ' of elements and attributes found. ' ' ' 'zPParse -v=always $XERCESCROOT/samples/data/personal.xml' ' Progressive parsing ' ' ' 'zSAX2Count $XERCESCROOT/samples/data/personal.xml ' ' Counts the elements, attributes, spaces and characters ' ' in an XML file ' ' ' 'zSAX2Print $XERCESCROOT/samples/data/personal.xml ' ' Parses an XML file and prints it out. ' ' ' ' ' # # Cannot continue the if test on several lines! # elif test "$1" = "zDOMCount" -o "$1" = "zDOMPrint" then echo '***' echo '*** xsamples.bat is starting the execution of '$1 echo '***' $1 -v=never $XERCESCROOT/samples/data/personal.xml echo echo echo elif test then echo echo echo '***' '*** Program has ended an returned control to xsamples.bat' '***' "$1" = "zPParse" -o "$1" = "zDOMPParse" '***' '*** xsamples.bat is starting the execution of '$1 '***' $1 -v=never $XERCESCROOT/samples/data/personal.xml echo echo echo elif test then echo echo echo '***' '*** Program has ended an returned control to xsamples.bat' '***' "$1" = "zSAX2Count" -o "$1" = "zSAX2Print" '***' '*** xsamples.bat is starting the execution of '$1 '***' $1 -v=never $XERCESCROOT/samples/data/personal.xml echo '***' echo '*** Program has ended an returned control to xsamples.bat' echo '***' 123 C++ and XML elif test then echo echo echo $1 "$1" = "zMemParse" '***' '*** xsamples.bat is starting the execution of '$1 '***' -v=never echo '***' echo '*** Program has ended an returned control to xsamples.bat' echo '***' else echo '*** ' echo '*** Program name not recognized:' $1 echo '*** ' fi 124 C++ and XML 5.3. Generate zsamples in Z/OS After the configuration has been established in the USS it is fairly straight forward to generate the Z/OS load modules. Set these variables if they arent't already: export LOADMOD=userid.SAMPLES.rel.LOAD export LOADEXP=hlq.SIXMEXP export CXX=c++ export CXXFLAGS="-2" export OS390_BIT64=1 (if running 64-bit support examples) export OS390_XPLINK=1 (if running 31-bit XPLINK support examples) export _CXX_CXXSUFFIX=cpp export _CXX_XSUFFIX_HOST=SIXMEXP export _CSS_CCMODE=1 Run gmake gmake These loadmodules are stored into your Z/OS load library: ZDOMCONT, ZDOMPPAR, ZDOMPRNT, ZMEMPARS, ZPPARSE, ZSAX2CNT and ZSAX2PRT. 125 C++ and XML 5.4. Execute zsamples in Z/OS An example of executing ZMEMPARS in a batch job in Z/OS is given below. //useridU JOB accnt,'Run module',CLASS=A Sure //* //* ----------------------------------------------------------------//* This job executes a module that was built by gmake from a cpp //* source in the USS. //* //* HFS is case sensitive - use Caps on //* ----------------------------------------------------------------//* // SET STEPLIB=userid.SAMPLES.REL.LOAD // SET IXMLOAD=hql.SIXMLOD1 // SET ZSAMPLE=ZMEMPARS //* //* ----------------------------------------------------------------//* - Run the example #1 //* ----------------------------------------------------------------//RUN01 EXEC PGM=&ZSAMPLE //STEPLIB DD DISP=SHR,DSN=&STEPLIB // DD DISP=SHR,DSN=&IXMLOAD /* The job dynamically allocates a sysout named SYS00001 and writes these lines to it Finished parsing the memory buffer containing the following XML statements: <?xml version='1.0' encoding='ibm-1047-s390'?> <!DOCTYPE company [ <!ELEMENT company (product,category,developedAt)> <!ELEMENT product (#PCDATA)> <!ELEMENT category (#PCDATA)> <!ATTLIST category idea CDATA #IMPLIED> <!ELEMENT developedAt (#PCDATA)> ]> <company> <product>XML4C</product> <category idea='great'>XML Parsing Tools</category> <developedAt> IBM Center for Java Technology, Silicon Valley, Cupertino, CA </developedAt> </company> Parsing took 51 ms (4 elements, 1 attributes, 0 spaces, 111 characters). 126 C++ and XML 6. How to use the XSLT Processor, C++ Edition In this section we explain how to prepare and run the IBM's examples about the XSLT processing. The setup is very much like the setup we walked through in the prior sections in this chapter. The xslt examples are located in the samples subfolder of the xslt installation folder, whose path is usually like usr/lpp/ixm/IBM/xslt4c-1_xx. They are: CompileStylesheet, SimpleTransform,UseStylesheetParam, DocumentBuilder, SimpleXPathAPI, XPathWrapper, ExternalFunction, SimpleXPathCAPI, XalanTransform, StreamTransform, XalanTransfomerCallback, ParseSourceWrappers, TraceListen, SerializeNodeSet and TransformToXercesDOM. Most examples in that set expect an input foo.xml, use a sytlesheet foo.xsl and produce a foo.out output. This section covers these topics: • Generate the xslt examples • Execute in the USS • Generate xslt examples in Z/OS • Execute in Z/OS Note, no configure utility needs to be executed prior to gmake. 127 C++ and XML 6.1. Generate the xslt examples in the USS Set up your environment. These variables comme in addition to the variables that are required for the XML parsing and that were detailed in the prior sections. These export commands can be issued manually or made permanent in the .profile. export XALANCROOT=/sys/usr/lpp/ixm/IBM/xslt4c-1_11 export XALANCOUT=/a/userid/xml Copy the examples to a private area mkdir /a/userid/xml/xslsamples cp -r $XALANCROOT/samples $XALANCOUT/xslsamples Every example comes in a folder under the same name as the program (in the below example CompileStylesheet). Most of these examples need one or more 'foo' input files, that are available in a subfolder in the folder that contains the program. As CompileStylesheet has the most extensive list of foo files included, we copy these to our private area and can use them with all examples. mkdir /a/userid/xml/foo cp $XALANCROOT/samples/CompileStylesheet/foo* 128 /a/userid/xml/foo C++ and XML 6.2. Execute the xslt examples in the USS In order to execute one of these examples • Go to the a/userid/foo folder • Adjust the path export PATH=$XALANCOUT/bin:$PATH Note The 'foo' files, including the foo.out output from these examples, are in ASCII. In order to best view these files you can copy them to a sequential data set in Z/OS, start a TSO/ISPF edit session in ASCII mode or issue the primary command 'SOURCE ASCII'' within the edit session. As suggested by the reading of the .xsl file this stylesheet intructs the Xalan transformer to select the 'doc' elements and change them into 'out' elements. Also the xml header is added the encoding attribute Here's the contents of the foo.xml file File Edit Edit_Settings Menu Utilities Compilers Test Help ------------------------------------------------------------------------------EDIT userid.XML.FOOXML Columns 00001 00072 ****** ***************************** Top of Data ****************************** 000001 <?xml version="1.0"?> <doc>Hello</doc> ****** **************************** Bottom of Data **************************** Here's the contents of the foo.xsl file in a TSO/ISPF edit session. The three lines we reproduced below are actually a single line of 216 characters. File Edit Edit_Settings Menu Utilities Compilers Test Help ------------------------------------------------------------------------------EDIT userid.XML.FOOXSL Columns 00001 00072 ****** ***************************** Top of Data ****************************** 000001 <?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999 ****** **************************** Bottom of Data **************************** // EDIT userid.XML.FOOXSL Columns 00073 00144 ****** ***************************** Top of Data ****************************** 000001 /XSL/Transform" version="1.0"> <xsl:template match="doc"> <out><xs ****** **************************** Bottom of Data **************************** // File Edit Edit_Settings Menu 129 Utilities Compilers Test Help C++ and XML ------------------------------------------------------------------------------EDIT userid.XML.FOOXSL Columns 00145 00216 ****** ***************************** Top of Data ****************************** 000001 l:value-of select="."/></out> </xsl:template> </xsl:stylesheet> ****** **************************** Bottom of Data **************************** Below is the contents of the foo.out file in a TSO/ISPf edit session File Edit Edit_Settings Menu Utilities Compilers Test Help ------------------------------------------------------------------------------EDIT userid.XML.FOOOUT Columns 00001 00072 ****** ***************************** Top of Data ****************************** 000001 <?xml version="1.0" encoding="UTF-8"?><out>Hello</out> ****** **************************** Bottom of Data **************************** 130 C++ and XML 6.3. Generate the xslt examples to Z/OS Once the configuration has been run in the USS it is fairly straight forward to generate the Z/OS load modules. Set these variables if they arent't already: export LOADMOD=userid.SAMPLES.rel.LOAD export LOADEXP=hlq.SIXMEXP export CXX=c++ export CXXFLAGS="-2" export OS390_BIT64=1 (if running 64-bit support examples) export OS390_XPLINK=1 (if running 31-bit XPLINK support examples) export _CXX_CXXSUFFIX=cpp export _CXX_XSUFFIX_HOST=SIXMEXP export _CSS_CCMODE=1 Run gmake gmake 131 C++ and XML 6.4. Execute the xslt examples in Z/OS The following loadmodules should have been generated: CMPSTYSH, DOCBLDR, EXTERNFN, SERNODES, SMPLTRNS, STRMTRNS, SXPTAPI, SXPTCAPI, TRACELSN, TRTXDOM, USESTYSH, XALNTCLB, XALNTRNS and XPATHWRP. Use a JCL like the below to execute in Z/OS //useridX JOB Accnt,'xslt example',CLASS=A //* //* ----------------------------------------------------------------//* This job executes a module that gmake generated from a source //* program in the USS (XML toolkit for z/OS). //* //* HFS is case sensitive - use Caps on //* ----------------------------------------------------------------//* // SET STEPLIB=userid.SAMPLES.REL.LOAD // SET IXMLOAD=hlq.SIXMLOD1 // SET EXAMPLE=TRACELSN //* //* ----------------------------------------------------------------//* - Run this example //* ----------------------------------------------------------------//RUN01 EXEC PGM=&EXAMPLE, // PARM= ':-tt' //* //STEPLIB DD DISP=SHR,DSN=&STEPLIB // DD DISP=SHR,DSN=&IXMLOAD Note Most examples do not execute well in Z/OS as there's no way to indicate where the foo files are located. An exception is the TRACELSN program, which does not expect any input and does not create any output. 132 C++ and XML 6.5. Fully generate a xslt example in Z/OS In the prior section the build of the Z/OS load modules was performed in the USS. In this section we see how an application can be entirely generated in a Z/OS batch job. Consider the SimpleTransform.cpp example that can be found in the USS. It is a simple program that includes the XalanMemoryManager.hpp. These sources will be copied to a Z/OS library and the loadmodule generated and executed in Z/OS. The SimpleTransform.cpp sources processes three files whose names are hardcoded and makes mandatory to execute with the current directory containing these files. We'll change that so the program can execute in a Z/OS environment as well. Copy and edit as follows • Copy SimpleTransform.cpp as SMPLTRNS member to the CPP library cp SimpleTransform.cpp "//'userid.BATCH.CPP(SMPLTRNS)'" • Copy XalanMemoryManager.hpp as XALANMMI to the HPP library cp XalanMemoryManager.hpp "//'userid.BATCH.HPP(XALANMMI)'" • Edit the SMPLTRNS member and change the includes to reference XALANMMI instead of XalanMemoryManager. Change the program so that SMLPTRNS program accepts three parameters. #include <xalanc/Include/PlatformDefinitions.hpp> #if defined(XALAN_CLASSIC_IOSTREAMS) #include <iostream.h> #else #include <iostream> #endif #include <xercesc/util/PlatformUtils.hpp> #include <xalanc/XalanTransformer/XalanTransformer.hpp> #include "XALANMMI.hpp" ..... /* * Add the support of file name parameters in order to execute * in Z/OS. * - parm #1 XML Input file * - parm #2 XSL Input file * - parm #3 Output file */ int 133 C++ and XML main( int argc, char* argv[]) { XALAN_USING_STD(cerr) XALAN_USING_STD(endl) int theResult = -1; char xmlFile[120]; char xslFile[120]; char outFile[120]; char* returnString; if (argc != 4) { cerr << "Error: Incorrect number of parameters: " << argc << endl << endl; cerr << "Usage: SimpleTransform input.xml input.xsl output" << endl << endl; } else // Don't verify the parameters. returnString = strncpy(xmlFile,argv[1],120); returnString = strncpy(xslFile,argv[2],120); returnString = strncpy(outFile,argv[3],120); cerr << "SMPLTRNS program will invoke the Xalan transformer " << "using the following files:" << endl << "\n Input : " << xmlFile << "\n : " << xslFile << "\n Output : " << outFile << endl << endl; try { XALAN_USING_XERCES(XMLPlatformUtils) XALAN_USING_XERCES(XMLUni) XALAN_USING_XALAN(XalanTransformer) XalanMemoryManagerImpl memoryManager; #ifdef XALAN_USE_ICU ..... #endif // Call the static initializer for Xerces. XMLPlatformUtils::Initialize( XMLUni::fgXercescDefaultLocale, 0, 0, &memoryManager ); 134 C++ and XML // Initialize Xalan. XalanTransformer::initialize( memoryManager ); { // Create a XalanTransformer. XalanTransformer theXalanTransformer( memoryManager ); // Pass user's parameters to the transformer theResult = theXalanTransformer.transform(xmlFile, xslFile, outFile); if(theResult != 0) { cerr << "SimpleTransform Error: \n" << theXalanTransformer.getLastError(); << endl << endl; } } ..... Use a JCL such as the below one to generate the SMPLTRNS loadmodule and execute it in Z/OS. //useridX JOB accnt,'XML CPP',CLASS=A,MSGCLASS=A, //* // SET MODULE=SMPLTRNS // SET IXMLOAD=hqual.SIXMLOD1 //* //JOBLIB DD DISP=SHR,DSN=CEE.SCEERUN // DD DISP=SHR,DSN=CEE.SCEERUN2 // DD DISP=SHR,DSN=CBC.SCCNCMP //* //* --------------------------------------------------------------//* CPPPROC procedure invokes the CPP compiler //* --------------------------------------------------------------//CPPPROC PROC MEMBER=, // SRCLIB= //COMPILE EXEC PGM=CCNDRVR,PARM='/CXX OPTFILE(DD:OPTS),OBJ,LIST' //SYSLIN DD DISP=SHR,DSN=&SYSUID..BATCH.OBJ(&MEMBER) //SYSPRINT DD SYSOUT=A //SYSIN DD DISP=SHR,DSN=&SRCLIB(&MEMBER) //SYSUT1 DD DUMMY //OPTS DD DUMMY // PEND //* --------------------------------------------------------------//* CPPLINK procedure invokes the linker in a CPP context //* --------------------------------------------------------------//CPPLINK PROC //LINK EXEC PGM=IEWL,PARM='OPTIONS=OPTS' //SYSLIB DD DISP=SHR,DSN=CEE.SCEELKEX // DD DISP=SHR,DSN=CEE.SCEELKED // DD DISP=SHR,DSN=CEE.SCEECPP // DD DISP=SHR,DSN=CEE.SCEELIB 135 C++ and XML // DD DISP=SHR,DSN=CBC.SCLBSID //SYSLIB1 DD DISP=SHR, // DSN=hqual.SIXMEXP //SYSLIB2 DD DISP=SHR,DSN=&SYSUID..BATCH.OBJ //SYSLMOD DD DISP=SHR,DSN=&SYSUID..BATCH.LOAD //SYSDEFSD DD DUMMY //SYSPRINT DD SYSOUT=A //SYSDEFSD DD DUMMY //OPTS DD DUMMY //SYSLIN DD DUMMY // PEND //* //* Compile SMPLTRNS //* //COMPILE EXEC PROC=CPPPROC, // MEMBER=SMPLTRNS, // SRCLIB=&SYSUID..BATCH.CPP //OPTS DD * LANGLVL(EXTENDED) NOSEARCH SEARCH( /usr/lpp/ixm/IBM/xml4c-5_7/include/, /usr/lpp/ixm/IBM/xslt4c-1_11/include/, /usr/lpp/ixm/IBM/xslt4c-1_11/include/xalanc/Include/, /usr/lpp/ixm/IBM/xslt4c-1_11/include/xalanc/XSLT/, //'userid.BATCH.+', //'CEE.SCEEH.+', //'CBC.SCLBH.+') DEFINE(OS390=1) DEFINE(_OPEN_THREADS=1) DEFINE(_XOPEN_SOURCE_EXTENDED=1) /* //* //* Build the module //* //LINK EXEC PROC=CPPLINK //OPTS DD * AMODE=31,RMODE=ANY DYNAM=DLL,ALIASES=NO,UPCASE=NO LIST=NO,MAP=NO,XREF=NO, REUS=RENT,EDIT=YES,AC=0,CALL=YES,CASE=MIXED /* //SYSLIN DD * INCLUDE SYSLIB(IOSTREAM) INCLUDE SYSLIB(COMPLEX) INCLUDE SYSLIB(C128N) INCLUDE SYSLIB1(IXM4C57X) INCLUDE SYSLIB1(IXMLC21X) INCLUDE SYSLIB2(SMPLTRNS) ENTRY CEESTART NAME SMPLTRNS(R) RC=0 /* //* //* Execute the module //* 136 C++ and XML //GO EXEC PGM=&MODULE, // PARM=('//a/userid/xml/foo/foo.xml /a/userid/xml/foo/foo.xsl //XML.T // ESTOUT') //STEPLIB DD DISP=SHR,DSN=&SYSUID..BATCH.LOAD // DD DISP=SHR,DSN=&IXMLOAD SMPLTRNS dynamically allocates a sysout and writes a report such as: ********************************* Top of Data ********************************** SMPLTRNS program will invoke the Xalan transformer using the following files: Input : /a/userid/xml/foo/foo.xml : /a/userid/xml/foo/foo.xsl Output : //XML.TESTOUT ******************************** Bottom of Data ******************************** SMPLTRNS dynamically allocates and creates the Z/OS data set 'XML.TESTOUT'. As the output is in ASCII use the 'SOURCE ASCII' command in the TSO/ISPF editor to reformat the output so that it is readable ****** ***************************** Top of Data ****************************** 000001 <?xml version="1.0" encoding="UTF-8"?><out>Hello</out> ****** **************************** Bottom of Data **************************** 137 C++ and XML 6.6. Execute the Xalan transformer directly The Xalan transformer may be invoked in the USS using line commands such as • Xalan -o foo.out foo.xml foo.xsl In the above command • Xalan (with an uppercase 'X') must be available in the PATH • -o means an output is written to the file whose name follows • foo.out, foo.xml and foo.xsl are very likely path/name expressions unless they all reside in the current directory. Enter Xalan with no parameter to display the usage message Xalan version 1.11.0. Xerces version 2.6.0. Usage: Xalan Ýoptions¨ source stylesheet Options: -a Use xml-stylesheet PI, not the 'stylesheet' argument -e encoding Force the specified encoding for the output. -i integer Indent the specified amount. -m Omit the META tag in HTML output. -o filename Write output to the specified file. -p name expression Sets a stylesheet parameter. -t Display timing information. -u Disable escaping of URLs in HTML output. -? Display this message. -v Validates source documents. A dash as the 'source' argument reads from stdin. ('-' cannot be used for both arguments.) The transformer may also be executed in a Z/OS batch job as shown below. The OUTFILE, INXML and INXSL allocations may reference files in the USS as well as data sets in Z/OS. //useridX JOB accnt,'Xalan',CLASS=A //* //* ----------------------------------------------------------------//* This job invokes the XALAN transformer. //* - IXMXAQ21 64-bit executable //* - IXMXAL21 31-bit executable //* //* HFS is case sensitive - use Caps on //* ----------------------------------------------------------------//* // SET IXMLOAD=hql.SIXMLOD1 //* //RUN01 EXEC PGM=IXMXAQ21, // PARM='/-e ibm-1047-s390 -o DD:OUTFILE DD:INXML DD:INXSL' 138 C++ and XML //STEPLIB DD DISP=SHR,DSN=&IXMLOAD //* //* Alternative syntaxes can be used to allocate a z/os file input //* //* PARM='///DD:XMLDATA(PERSONAL)' //* PARM='DD:XMLDATA(PERSONAL)' //* //* PARM='"//''userid.XML.DATA(PERSONAL)''"' //* PARM='"//XML.DATA(PERSONAL)"' (automatic prefixation) //* //OUTFILE DD SYSOUT=* //INXML DD PATH='/a/userid/xml/foo/foo.xml',PATHOPTS=ORDONLY //INXSL DD PATH='/a/userid/xml/foo/foo.xsl',PATHOPTS=ORDONLY 139 C++ and XML 6.7. Execute the test XSLT utility Along with the XALAN transformer a test XSLT transformer is provided. It offers additional options over the regular XALAN utility. Prior to executing the test XSLT transformer make sure these variables are set: • XALANCROOT • XERCESCROOT • The PATH must include the $XALANCROOT/bin location • The LIBPATH must include the $XALANCROOT/lib and $XERCESCROOT/lib locations The test XSLT utility can be executed in a number of ways • Type testXSLT with no option in the command line and enter options at the keyboard • Type testXSLT -h in order to display the full list of options • Type testXSLT in the command line, followed by the options necessary to perform the desired task testXSLT [-option [-option] ... ] The test XSLT transformer may also be executed in a Z/OS batch job //userid$ JOB accnt,'Xalan',CLASS=A //* //* ----------------------------------------------------------------//* This job invokes the XALAN transformer and prints a trace to a //* dynamically allocated sysout. //* - IXMTSQ21 64-bit executable //* - IXMTST21 31-bit executable //* //* HFS is case sensitive - use Caps on //* ----------------------------------------------------------------//* // SET IXMLOAD=hql.SIXMLOD1 //* //RUN01 EXEC PGM=IXMTSQ21, // PARM='/-ttc -out DD:OUTFILE -in DD:INXML -xsl DD:INXSL' //STEPLIB DD DISP=SHR,DSN=&IXMLOAD //OUTFILE DD SYSOUT=* //INXML DD PATH='/a/userid/xml/foo/foo.xml',PATHOPTS=ORDONLY //INXSL DD PATH='/a/userid/xml/foo/foo.xsl',PATHOPTS=ORDONLY Here's the full list of options that the test XLST utility accepts 140 C++ and XML TestXSLT options: Options are case-sensitive. [-? Shows this message.] [-h Shows this message.] [-in <source URL> (If not specified, stdin is used.)] [-xsl <stylesheet URL>] [-out <output file>] [-v Show version information only.] [-qc Quiet pattern conflicts warnings.] [-q Use quiet mode.] [-indent n Controls how many spaces to indent. (default is 0)] [-validate Controls whether validation occurs. Validation is off by default.] [-tt Trace the templates as they are being called.] [-tg Trace each generation event.] [-ts Trace each selection event.] [-ttc Trace the template children as they are being processed.] [-xml Use XML formatter.] [-text Use Text formatter.] [-html Use HTML formatter.] [-dom Use DOM formatter. Generates a DOM instance, then formats XML for output.] [-xst Use source tree formatter. Generates an instance of the default source tre [-param name expression Sets a stylesheet parameter.] [-xd Use Xerces DOM instead of Xalan source tree.] [-de Disable built-in extension functions.] The following option is valid only with -html. [-noindent Turns off HTML indenting. The following option is valid only with -xml. [-nh Don't generate the XML declaration.] 141 C++ and XML 7. How to call the XML Toolkit from a Cobol program This section shows an example of building an application that consists of a Cobol main program that invokes the XML toolkit in C subroutines. The C routines will reside in a DLL. As a Cobol program cannot call a C DLL directly, an intermediate program is required. The application is structured as detailed below. • SPFEXML program is the Cobol main program. • A1CCDLGTprogram is the cpp intermediate program • SAXPRSE and SAXHNDL are the cpp sources • SAXPRSEH and SAXHNDLH are the hpp includes • personal-schema.xml and personal.xsd are the test inputs for the SPFEXML program For the convenience's sake the SPFEXML, A1CCDLGT, SAXPRSE and SAXHNDL programs will be stored in the CPP library and SAXPRSEH and SAXHNDLH includes will be stored in the HPP library. 142 C++ and XML 7.1. Set up the test files for the SPFEXML application It is recommended to copy the personal-schema.xml and personal.xsd files from the IBM location to a private location. In the below commands we assume the variable $XERCESCROOT contains the path to the IBM's examples and /a/userid/xml/samples is the target location. cp $XERCESCROOT/data/samples/personal-schema.xml /a/userid/xml/samples/personal-schema.xml cp $XERCESCROOT/data/samples/personal.xsd /a/userid/xml/samples/personal.xsd Create in the userid.BATCH.XML library a member named INVALID with the below contents. Although apparently correct these XML lines do not conform to the personal.xsd specification <?xml version="1.0" encoding="ibm-1140"?> <personnel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation= '/a/userid/xml/samples/personal.xsd'> <person id="Big.Boss"> <name><family>Boss</family> <given>Big</given></name> <email>chief@foo.com</email> <link subordinates="one.worker two.worker"/> </person> <person id="one.worker"> <name><family>Worker</family> <given>One</given></name> <link manager="Big.Boss"/> <email>one@foo.com</email> </person> <person id="two.worker"> <name><family>Worker</family> <given>Two</given></name> <email>two@foo.com</email> <link manager="Big.Boss"/> <phone>+1.123.555.1234</phone> </person> </personnel> 143 C++ and XML 7.2. The SPFEXML cobol program This program does the following: • Calls A1CCDLGT program to get the entry point of the validate_parse function in SAXPRSE DLL • Invokes parse_validate against the file name hardcoded in fileName field • Invokes parse_validate against a resource that is referenced by its DD name: INVALID Process pgmname(longmixed),noexportall,outdd(sysprint),nodynam Title 'COBOL program SPFEXML.' IDENTIFICATION DIVISION. PROGRAM-ID 'SAXParseFrontEnd'. AUTHOR. PATRICE. *REMARKS. This program is an example published by IBM * in the XML Toolkit's user guide, Appendix B * Note the nodynam compilation option. DATE-WRITTEN. 20 Jan 2015. DATE-COMPILED. SECURITY. Confidentiality level. DATA DIVISION. * ---------------------------------------------------* WORKING-STORAGE SECTION. * ---------------------------------------------------WORKING-STORAGE SECTION. 01 fileName pic x(80) value z'/a/userid/xml/samples/personal-schema.xml'. 01 invalidFile pic x(12) value z'DD:INVALID'. 01 rc pic s9(9) comp-5. 01 fnlen pic 99. * ** The below fields for the C DLL support. 01 DLL-INFO. 03 DLL-LOADMOD-NAME PIC X(12) value spaces. 03 DLL-PROGRAM-NAME PIC X(160) value spaces. 03 DLL-PROGRAM-HANDLE usage pointer. 01 DLL-RC PIC S9(9) binary. 01 DLL-PROGRAM-PTR PROCEDURE-POINTER. 01 DLL-STATUS PIC X(1) value 'N'. 88 DLL-LOADED value 'Y'. 88 DLL-NOT-LOADED value 'N'. 01 Retvalue PIC S9(9) comp. / * ---------------------------------------------------* PROCEDURE DIVISION. * ---------------------------------------------------PROCEDURE DIVISION. MAIN-SECTION. * Call A1CCDLGT utility to retrieve parse_valide function IF DLL-NOT-LOADED THEN MOVE z'SAXPRSE' 144 to DLL-LOADMOD-NAME C++ and XML MOVE z'parse_validate' to DLL-PROGRAM-NAME CALL 'A1CCDLGT' using by reference DLL-INFO by reference DLL-RC IF DLL-RC = 0 THEN SET DLL-LOADED to true ELSE DISPLAY 'A1CCLDGT failed with Rc=' DLL-RC MOVE 16 to RETURN-CODE STOP RUN END-IF END-IF SET DLL-PROGRAM-PTR to DLL-PROGRAM-HANDLE * Try a valid file. * ** Call 'parse_validate' Call DLL-PROGRAM-PTR using by value address of fileName returning rc Move 0 to tally Inspect fileName tallying tally for characters before x'00' If rc = 0 Display '"' fileName(1:tally) '" is valid.' Else Display '"' fileName(1:tally) '" is invalid!' End-if * Try now a well-formed but invalid file, accessed * by DDName INVALID. * ** Call 'parse_validate' Call DLL-PROGRAM-PTR using by value address of invalidFile returning rc Move 0 to tally Inspect invalidFile tallying tally for characters before x'00' If rc = 0 Display '"' invalidFile(1:tally) '" was supposedly invalid (?).' Move 8 to return-code Else Display '"' invalidFile(1:tally) '" is invalid as expected.' End-if Goback. End program 'SAXParseFrontEnd'. 145 C++ and XML 146 C++ and XML 7.3. The A1CCDLGT program A1CCDLGT is a generic program that can be used to retrieve the entry point of a function within a DLL and pass the address back to a Cobol caller. A1CCDLGT must be linked together with the Cobol main program. /* * A1CCDLGT is part of an example in the IBM's MAINFRAME-DLLS.doc * document. * * A cobol program cannot invoke a C/C++ DLL directly it can only * do that through an intermediate program such as A1CCDLGT. * * A1CCDLGT is expecting a DLL module name and a function name * within the DLL. The entry point of the function is returned * to the caller that can use it run the DLL. * * Note the pragma linkage. * */ #include <stdio.h> #include <dll.h> #pragma linkage (A1CCDLGT,COBOL) typedef struct dll_lm { char dll_loadmod_name[12]; char dll_func_name[160]; void (*fptr) (void); } dll_lm; void A1CCDLGT (dll_lm *dll, int *rc) { dllhandle *handle; void (*fptr1) (void); *rc = 0; /* Load the DLL using the C runtime services */ handle = dllload(dll->dll_loadmod_name); if (handle == NULL) { perror("A1CCDLGT failed on call to load DLL.\n"); *rc = 1; return; } /* Load succeeded, get its entry point */ fptr1 = (void (*) (void)) dllqueryfn(handle,dll->dll_func_name); if (fptr1 == NULL) { perror("A1CCDLGT failed on retrieving function.\n"); *rc = 2; return; } 147 C++ and XML /* Function has been located, return its entry point */ printf("A1CCDLGT returned the pointer of function %s in ddl %s", dll->dll_func_name, dll->dll_loadmod_name, "\n"); dll->fptr = fptr1; return; } 148 C++ and XML 7.4. The SAXPRSE program This program invokes the SAXParser parser against the xmlFilePath file object /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * $Log: SAXParse.cpp,v $ * Created by Patrice Cotte per the XML Toolkit user's guide Appendix B * * The xercesc includes are part of the XML toolkit currently at: * $XERCESCROOT/include/xercesc * * xercesc contains subfolders sax, util, parsers, dom, internal * zparsers, validators, framework, sax2 */ // --------------------------------------------------------------------------// Includes // --------------------------------------------------------------------------#include <xercesc/parsers/SAXParser.hpp> #include <xercesc/util/OutOfMemoryException.hpp> #include "SAXPRSEH.hpp" #include "stdio.h" // --------------------------------------------------------------------------// Function prototypes // -----------------------------------------------------------------------extern "C" { int parse_validate(char * xmlFilePath); } // -----------------------------------------------------------------------// Parse_validate initializes the parser environment and does a single // parse of the XML document specified in the parameter list. 149 C++ and XML // It terminates and cleans up the environment before exiting. // -----------------------------------------------------------------------int parse_validate(char * xmlFilePath) { bool error_occurred = false; bool warning_occurred = false; unsigned long duration; SAXParser * parser; SAXParseHandlers * handler; // Initialize the XML4C2 system try { XMLPlatformUtils::Initialize(); } catch (const OutOfMemoryException&) { XERCES_STD_QUALIFIER cerr << "OutOfMemoryException " << "during initialization! " << XERCES_STD_QUALIFIER endl; return 8; } catch (const XMLException& toCatch) { XERCES_STD_QUALIFIER cerr << "Error during initialization! :\n" << StrX(toCatch.getMessage()) << XERCES_STD_QUALIFIER endl; return 1; } catch (...) { XERCES_STD_QUALIFIER cerr << "Error during initialization! :" << XERCES_STD_QUALIFIER endl; return 8; } // // Create a SAX parser object and set options. // parser = new SAXParser; parser->setDoNamespaces(true); parser->setDoSchema(true); parser->setValidationSchemaFullChecking(true); parser->setValidationScheme(SAXParser::Val_Auto); handler = new SAXParseHandlers(); parser->setErrorHandler(handler); // // // Kick off parse catching exceptions. 150 C++ and XML try { const unsigned long startMillis = XMLPlatformUtils:: getCurrentMillis(); parser->parse(xmlFilePath); const unsigned long endMillis = XMLPlatformUtils:: getCurrentMillis(); duration = endMillis - startMillis; } catch (const OutOfMemoryException&) { XERCES_STD_QUALIFIER cerr << "OutOfMemoryException" << XERCES_STD_QUALIFIER en error_occurred = true; } catch (const XMLException& e) { XERCES_STD_QUALIFIER cerr << "\nError during parsing: \n" << StrX(e.getMessage()) << XERCES_STD_QUALIFIER endl; error_occurred = true; } catch (...) { XERCES_STD_QUALIFIER cerr << "Error during parsing: \n" << XERCES_STD_QUALIFIER endl; error_occurred = true; } if (handler->getSawErrors()) { error_occurred = true; } if (handler->getSawWarnings()) { warning_occurred = true; } if (!error_occurred) { XERCES_STD_QUALIFIER cout << xmlFilePath << ": " << duration << " MS " << XERCES_STD_QUALIFIER endl; } // // Delete the parser itself. // delete handler; delete parser; Must be done prior to calling Terminate, below. // And call the termination method XMLPlatformUtils::Terminate(); if (error_occurred) return 8; else if (warning_occurred) return 4; else return 0; } 151 C++ and XML 152 C++ and XML 7.5. The SAXHNDL program This program is the error handler for the SAXPRSE program /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * $Log: SAXParseHandlers.cpp,v $ * * Created by Patrice Cotte January 21, 2015 * Reason Cobol/SAX example per the XML Toolkit User's guide * Appendix B * */ // --------------------------------------------------------------------------// Includes // --------------------------------------------------------------------------#include <xercesc/sax/SAXParseException.hpp> #include <xercesc/util/XMLString.hpp> #include <xercesc/util/XMLUniDefs.hpp> #include "SAXPRSEH.hpp" // --------------------------------------------------------------------------// SAXParseHandlers: Constructors and Destructor // --------------------------------------------------------------------------SAXParseHandlers::SAXParseHandlers() : fSawErrors(false) ,fSawWarnings(false) { } SAXParseHandlers::~SAXParseHandlers() { } 153 C++ and XML // --------------------------------------------------------------------------// SAXParseHandlers: Overrides of the SAX Errorhandler interface // --------------------------------------------------------------------------void SAXParseHandlers::error(const SAXParseException& e) { fSawErrors = true; XERCES_STD_QUALIFIER cerr << "\n Error at (file " << StrX(e.getSystemId()) << ", line " << e.getLineNumber() << ", char " << e.getColumnNumber() << ") : " << StrX(e.getMessage()) << XERCES_STD_QUALIFIER endl; } void SAXParseHandlers::fatalError(const SAXParseException& e) { fSawErrors = true; XERCES_STD_QUALIFIER cerr << "\n Fatal error at (file " << StrX(e.getSystemId()) << ", line " << e.getLineNumber() << ", char " << e.getColumnNumber() << ") : " << StrX(e.getMessage()) << XERCES_STD_QUALIFIER endl; } void SAXParseHandlers::warning(const SAXParseException& e) { fSawWarnings = true; XERCES_STD_QUALIFIER cerr << "\n Warning at (file " << StrX(e.getSystemId()) << ", line " << e.getLineNumber() << ", char " << e.getColumnNumber() << ") : " << StrX(e.getMessage()) << XERCES_STD_QUALIFIER endl; } void SAXParseHandlers::resetDocument() { fSawWarnings = false; fSawErrors = false; } 154 C++ and XML 7.6. The SAXPRSEH include /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * $Log: SAXParse.hpp,v $ * * Created by Patrice Cotte Janauary 25, 2015 * Reason Cobol/SAX example per the XML Toolkit user's guide * Appendix B */ // --------------------------------------------------------------------------// Includes for all the program files to see // --------------------------------------------------------------------------#include <string.h> #include <stdlib.h> #if defined(XERCES_NEW_IOSTREAMS) #include <iostream> #else #include <iostream.h> #endif #include <xercesc/util/PlatformUtils.hpp> #include <xercesc/parsers/SAXParser.hpp> #include "SAXHNDLH.hpp" // --------------------------------------------------------------------------// This is a simple class that lets us do easy (though not terribly efficient) // trancoding of XMLCh data to local code page for display. // --------------------------------------------------------------------------class StrX { public : // ----------------------------------------------------------------------// Constructors and Destructor 155 C++ and XML // ----------------------------------------------------------------------StrX(const XMLCh* const toTranscode) { // Call the private transcoding method fLocalForm = XMLString::transcode(toTranscode); } ~StrX() { XMLString::release(&fLocalForm); } // ----------------------------------------------------------------------// Getter methods // ----------------------------------------------------------------------const char* localForm() const { return fLocalForm; } private : // ----------------------------------------------------------------------// Private data members // // fLocalForm // This is the local code page form of the string. // ----------------------------------------------------------------------char* fLocalForm; }; inline XERCES_STD_QUALIFIER ostream& operator<<(XERCES_STD_QUALIFIER ostream& target, const StrX& toDump) { target << toDump.localForm(); return target; } 156 C++ and XML 7.7. The SAXHNDLH include /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * $Log: SAXParseHandlers.hpp,v $ * * Created by Patrice Cotte * Reason Cobol/SAX example * * */ #include January 21, 2015 per the XML Toolkit User's guide Appendix B <xercesc/sax/HandlerBase.hpp> XERCES_CPP_NAMESPACE_USE class SAXParseHandlers : public HandlerBase { public: // ---------------------------------------------------------------------// Constructor and Destructor // ---------------------------------------------------------------------SAXParseHandlers(); ~SAXParseHandlers(); // ---------------------------------------------------------------------// Handlers for the SAX ErrorHandler interface // ---------------------------------------------------------------------void warning(const SAXParseException& exception); void error(const SAXParseException& exception); void fatalError(const SAXParseException& exception); // ---------------------------------------------------------------------// Implementations of the SAX ErrorHandler interface 157 C++ and XML // ---------------------------------------------------------------------bool getSawErrors() const { return fSawErrors; } bool getSawWarnings() const { return fSawWarnings; } void resetDocument(); private: bool fSawErrors; bool fSawWarnings; }; 158 C++ and XML 7.8. The JCL The JCl includes three procedures in-stream. These procedures might be stored in a procedure library (proclib). //useridX JOB accnt,'COB XML Toolkit',CLASS=A,MSGCLASS=A //* // SET MODULE=SPFEXML // SET IXMLOAD=hqual.SIXMLOD1 //* //JOBLIB DD DISP=SHR,DSN=CEE.SCEERUN // DD DISP=SHR,DSN=CEE.SCEERUN2 // DD DISP=SHR,DSN=CBC.SCCNCMP //* //* --------------------------------------------------------------//* CPPPROC procedure invokes the CPP compiler //* --------------------------------------------------------------//CPPPROC PROC MEMBER=, // SRCLIB=, // CPARM='CXX OPTFILE(DD:OPTS),OBJ' //CPPCOMP EXEC PGM=CCNDRVR, // PARM='/&CPARM' //SYSLIN DD DISP=SHR,DSN=&SYSUID..BATCH.OBJ(&MEMBER) //SYSPRINT DD SYSOUT=A //SYSOUT DD SYSOUT=A //SYSERR DD SYSOUT=A //SYSIN DD DISP=SHR,DSN=&SRCLIB(&MEMBER) //SYSUT1 DD DUMMY //OPTS DD DUMMY // PEND //* --------------------------------------------------------------//* CPPLINK procedure invokes the linker in a CPP context //* --------------------------------------------------------------//CPPLINK PROC //LINK EXEC PGM=IEWL,PARM='OPTIONS=OPTS' //SYSLIB DD DISP=SHR,DSN=CEE.SCEELKEX // DD DISP=SHR,DSN=CEE.SCEELKED // DD DISP=SHR,DSN=CEE.SCEECPP // DD DISP=SHR,DSN=CBC.SCLBSID //SYSLIB1 DD DISP=SHR, // DSN=hqual.SIXMEXP //SYSLIB2 DD DISP=SHR,DSN=&SYSUID..BATCH.OBJ //SYSLMOD DD DISP=SHR,DSN=&SYSUID..BATCH.LOAD //SYSDEFSD DD DUMMY //SYSPRINT DD SYSOUT=A //SYSDEFSD DD DUMMY //OPTS DD DUMMY //SYSLIN DD DUMMY // PEND //* --------------------------------------------------------------//* Compile and Link Cobol procedure //* --------------------------------------------------------------- 159 C++ and XML //COBLPROC PROC MEMBER=, MEMBER NAME // MODULE=, MODULE NAME // COBPRM1='APOST,DYNAM,LIB,LIST,MAP,OPT,RENT', // COBPRM2='NOSSR,NOSEQ,TRUNC(BIN),XREF', // LNKPARM='RENT,REUS,LET' //COBCOMP EXEC PGM=IGYCRCTL,REGION=4M, // PARM=(&COBPRM1, // &COBPRM2) //STEPLIB DD DSN=hqualcob.SIGYCOMP,DISP=SHR //SYSPRINT DD SYSOUT=A //SYSLIB DD DSN=hqualcob.SIGYSAMP,DISP=SHR //SYSLIN DD DSNAME=&&LOADSET,UNIT=VIO,DISP=(NEW,PASS), // SPACE=(CYL,(1,1)) //SYSIN DD DSN=&SYSUID..BATCH.CPP(&MEMBER),DISP=SHR //SYSUT1 DD UNIT=VIO,SPACE=(CYL,(1,1)) //SYSUT2 DD UNIT=VIO,SPACE=(CYL,(1,1)) //SYSUT3 DD UNIT=VIO,SPACE=(CYL,(1,1)) //SYSUT4 DD UNIT=VIO,SPACE=(CYL,(1,1)) //SYSUT5 DD UNIT=VIO,SPACE=(CYL,(1,1)) //SYSUT6 DD UNIT=VIO,SPACE=(CYL,(1,1)) //SYSUT7 DD UNIT=VIO,SPACE=(CYL,(1,1)) //SYSUT8 DD UNIT=VIO,SPACE=(CYL,(1,1)) //* //COBLINK EXEC PGM=IEWL, // PARM='LIST,MAP,&LNKPARM', // COND=(5,LT,COBCOMP),REGION=4M //SYSPRINT DD SYSOUT=A //SYSLIB DD DSN=CEE.SCEELKED,DISP=SHR // DD DSN=hqualcob.SIGYCOMP,DISP=SHR //SYSUT1 DD UNIT=VIO,DCB=BLKSIZE=1024,SPACE=(CYL,(1,1)) //SYSLMOD DD DSN=&SYSUID..BATCH.LOAD(&MODULE),DISP=SHR //SYSLIN DD DSNAME=&&LOADSET,DISP=(OLD,DELETE) // DD DDNAME=SYSIN // PEND //* //* Compile SAXPRSE //* //COMPSAX EXEC PROC=CPPPROC, // MEMBER=SAXPRSE, // SRCLIB=&SYSUID..BATCH.CPP //OPTS DD * DLL,EXPORTALL LANGLVL(EXTENDED) LIST,OFFSET,SOURCE,XREF NOSEARCH SEARCH( /usr/lpp/ixm/IBM/xml4c-5_7/include/, //'userid.BATCH.+', //'CEE.SCEEH.+', //'CBC.SCLBH.+') DEFINE(OS390=1) DEFINE(_OPEN_THREADS=1) DEFINE(_XOPEN_SOURCE_EXTENDED=1) /* //* 160 C++ and XML //* Compile SAXHNDL //* //COMPSAXH EXEC PROC=CPPPROC, // MEMBER=SAXHNDL, // SRCLIB=&SYSUID..BATCH.CPP //OPTS DD * LANGLVL(EXTENDED) LIST,OFFSET,SOURCE,XREF NOSEARCH SEARCH( /usr/lpp/ixm/IBM/xml4c-5_7/include/, //'userid.BATCH.+', //'CEE.SCEEH.+', //'CBC.SCLBH.+') DEFINE(OS390=1) DEFINE(_OPEN_THREADS=1) DEFINE(_XOPEN_SOURCE_EXTENDED=1) /* //* Build the module - LIST=YES and/or MAP=YES and/or XREF=YES //* to get the details of the linked module //* - DYNAM=DLL lets the binder //* * Write IMPORTS to the SUBDEFSD (side-deck) //* * Create IEWBLIT (Loader info table) //* * Create IEWBCIE (Compiler Import/export tbl) //* This option should be used when the module is a //* DLL or will load DLLs. //LINKSAX EXEC PROC=CPPLINK //OPTS DD * AMODE=31,RMODE=ANY DYNAM=DLL,ALIASES=NO,UPCASE=NO LIST=NO,MAP=YES,XREF=YES REUS=RENT,EDIT=YES,AC=0,CALL=YES,CASE=MIXED /* //SYSLIN DD * INCLUDE SYSLIB(IOSTREAM) INCLUDE SYSLIB1(IXM4C57X) INCLUDE SYSLIB2(SAXHNDL) INCLUDE SYSLIB2(SAXPRSE) ENTRY CEESTART NAME SAXPRSE(R) RC=0 /* //* //* Compile and link the A1CCDLGT intermediate program //* //COMPA1CC EXEC PROC=CPPPROC, // MEMBER=A1CCDLGT, // SRCLIB=&SYSUID..BATCH.CPP, // CPARM='OPTFILE(DD:OPTS)' //OPTS DD * NOSEARCH SEARCH('CEE.SCEEH.+') NOOPT SO OBJ DLL RENT LONGNAME /* //LINKA1CC EXEC PROC=CPPLINK //OPTS DD * AMODE=31,MAP RENT,DYNAM=DLL 161 C++ and XML CASE=MIXED /* //SYSLIN DD * INCLUDE SYSLIB(IOSTREAM) INCLUDE SYSLIB2(A1CCDLGT) NAME A1CCDLGT(R) RC=0 /* //* //* Compile and link the Cobol main program SPFEXML //* //COMPSPFE EXEC PROC=COBLPROC,MODULE='SPFEXML', // MEMBER='SPFEXML' //COBLINK.SYSLIB DD DISP=SHR,DSN=CEE.SCEELKED // DD DISP=SHR,DSN=SYS1.LINKLIB // DD DISP=SHR,DSN=&SYSUID..BATCH.LOAD //* //* Execute the module //* //GO EXEC PGM=&MODULE //STEPLIB DD DISP=SHR,DSN=&SYSUID..BATCH.LOAD // DD DISP=SHR,DSN=&IXMLOAD //INVALID DD DISP=SHR,DSN=&SYSUID..BATCH.XML(INVALID) //CEEDUMP DD SYSOUT=* 162 C++ and XML 7.9. The outputs produced by the SPFEXML application These outputs should be obtained: ********************************* Top of Data ********************************** "/a/userid/xml/samples/personal-schema.xml" is valid. "DD:INVALID" is invalid as expected. ******************************** Bottom of Data ******************************** ********************************* Top of Data ********************************** Error at (file DD:INVALID, line 1, char 1210) : Element 'email' is not valid for content model: '((name,email,url),link)' Error at (file DD:INVALID, line 1, char 1691) : Unknown element 'phone' Error at (file DD:INVALID, line 1, char 1770) : Element 'phone' is not valid for content model: '((name,email,url),link)' ******************************** Bottom of Data ******************************** ********************************* Top of Data ********************************** A1CCDLGT returned the pointer of function parse_validate in ddl SAXPRSE ******************************** Bottom of Data ******************************** 163 Chapter 4. Conclusion If you tried all the examples in this book - and I have no doubt you did! - you really deserve congratulations! I'd like to thank you for your time and the interest you found in this book. Many interesting and various topics in the programming across different environments in Z/OS and using different languages have been covered. Your vision is now wider and you have taken several steps to the modern world. 164