Disoriented by SAX vs. DOM? Baffled by XML APIs? You are not alone. Writing RPGLE code to parse XML documents can be a tedious task. There is, however, a (free) utility called Xalan that will immensely ease your job, and let concentrate on the business rather than the bytes.
Xalan is a Java XSL parser, that will take as input 2 XML files: The first is the XML we want to transform, and the second is a XML file that defines the transformation. The transformation can output another XML, an HTML file, a PDF file (using special extensions).
Of special interest to iSeries professionals is the fact that a transformation can output a regular, flat text file, that is suited for import into a DB2 table.
You can find many examples of XSL transformations on the Web, but here is a real world example that is relevant in our context.
The Bank of Israel publishes a daily XML file with the currency rates.
With the attached code, you can find a sample of this file, and the XSL to transform it into a Comma Separated Values text file.
The result file can be imported into a DB2 table using CPYFRMIMPF command.
How to get Xalan to your iSeries computer?
-----------------------------------------------------------------
If you have VRR1, and have Java, then chances are that it is already installed.Type WRKLNK OBJ('/QIBM/ProdData/OS400/xml/lib/*')
If you see the files xalan101.jar and xerces103.jar then you are already set up.
If you do not have the files, you can get them at here.
Note: This is an OLD version of Xalan. New version are available, but have not been tried by me, yet. If you decide to use a newer Xalan distribution, pay attention to the CLASSPATH variable.
Create a new IFS directory called XML:
MKDIR '/xml'
Transfer the ZIP file via FTP to the XML directory.
Run the following command (it's best to submit to batch):
QSH CMD('cd /xml; ajar -x -r xalan-j_1_0_1.zip')
About the attached code:
=================================================================
The CL program takes 5 parameters:
XML - The file to be translated.
XSL - The transformation description.
OUT - The result file.
CSSID - The code page of the result file.
VER - The AS/400 version. If *PRV, the script assumes that you installed Xalan manually according to the above listed instructions. Use *PRV in case you did not find the xalan101.jar file,
even if you have 5.1 or higher.
XALAN *cmd:
=================================================================
/* CRTCMD CMD(XALAN) PGM(*LIBL/XALANCPP) ... */
CMD PROMPT('Translate XML using XSLT')
PARM KWD(XML) TYPE(*PNAME) LEN(256) MIN(1) +
CASE(*MIXED) PROMPT('Full XML file path')
PARM KWD(XSL) TYPE(*PNAME) LEN(256) MIN(1) +
CASE(*MIXED) PROMPT('Full XSL file path')
PARM KWD(out) TYPE(*PNAME) LEN(256) MIN(1) +
CASE(*MIXED) PROMPT('Full Result file path')
PARM KWD(CCSID) TYPE(*CHAR) LEN(7) PROMPT('CCSID +
of result file')
PARM KWD(VER) TYPE(*CHAR) LEN(7) RSTD(*YES) +
DFT(V5R1M0) VALUES(V5R1M0 V5R2M0 *PRV) +
PROMPT('OS400 release')
/* End of Command XALAN */
XALANCPP *PGM:
=============================================================
PGM PARM(&XML &XSL &OUT &CCSID &VER)
DCL VAR(&JAVA) TYPE(*CHAR) LEN(1024)
DCL VAR(&qshell) TYPE(*CHAR) LEN(1024)
DCL VAR(&XML) TYPE(*CHAR) LEN(256)
DCL VAR(&XSL) TYPE(*CHAR) LEN(256)
DCL VAR(&OUT) TYPE(*CHAR) LEN(256)
DCL VAR(&CCSID) TYPE(*CHAR) LEN(7)
DCL VAR(&VER) TYPE(*CHAR) LEN(6)
/* Prepare java call */
IF COND(&VER = '*PRV') THEN(DO)
CHGVAR VAR(&JAVA) VALUE('java -classpath +
/xml/xalan_1_0_1/xalan.jar:/xml/xalan_1_0_1+
/xerces.jar:. +
org.apache.xalan.xslt.Process ' *BCAT +
'-IN ' *BCAT &XML *BCAT ' -XSL ' *BCAT +
&XSL *BCAT ' -OUT ' *BCAT &OUT *BCAT ' +
-TEXT')
enddo
ELSE CMD(DO)
CHGVAR VAR(&JAVA) VALUE('java -classpath +
/QIBM/ProdData/OS400/xml/lib/xalan101.jar:/+
QIBM/ProdData/OS400/xml/lib/xerces103.jar:. +
org.apache.xalan.xslt.Process ' *BCAT +
'-IN ' *BCAT &xml *BCAT ' -XSL ' *BCAT +
&xsl *BCAT ' -OUT ' *BCAT &out *BCAT ' -TEXT'
enddo
STRQSH CMD(&JAVA)
/* Change CCSID of OUT file
CHGVAR VAR(&QSHELL) VALUE('setccsid' *bcat &ccsid *BCAT &out)
STRQSH CMD(&qshell)
RETURN
EXIT: ENDPGM
/* End of Program XALANCPP */
Sample XML to translate:
Note: The encoding in the original XML file is wrong.
==============================================================
<?xml version="1.0" encoding="iso-8859-8" standalone="yes"?> <CURRENCIES> <LAST_UPDATE> 2002-10-21</LAST_UPDATE> <CURRENCY> <NAME> unit</NAME> <UNIT> 1</UNIT> <COUNTRY> Currency basket</COUNTRY> <RATE> 4.938</RATE> <CHANGE> -0.315</CHANGE> </CURRENCY> <CURRENCY> <NAME> dollar</NAME> <UNIT> 1</UNIT> <COUNTRY> USA</COUNTRY> <RATE> 4.745</RATE> <CHANGE> -0.357</CHANGE> </CURRENCY> <CURRENCY> <NAME> pound</NAME> <UNIT> 1</UNIT> <COUNTRY> Great Britain</COUNTRY> <RATE> 7.3398</RATE> <CHANGE> -0.473</CHANGE> </CURRENCY> <CURRENCY> <NAME> yen</NAME> <UNIT> 100</UNIT> <COUNTRY> Japan</COUNTRY> <RATE> 3.8057</RATE> <CHANGE> 0.076</CHANGE> </CURRENCY> <CURRENCY> <NAME> euro</NAME> <UNIT> 1</UNIT> <COUNTRY> European Monetary Union</COUNTRY> <RATE> 4.62</RATE> <CHANGE> -0.244</CHANGE> </CURRENCY> <CURRENCY> <NAME> dollar</NAME> <UNIT> 1</UNIT> <COUNTRY> Australia</COUNTRY> <RATE> 2.6299</RATE> <CHANGE> 0.221</CHANGE> </CURRENCY> <CURRENCY> <NAME> dollar</NAME> <UNIT> 1</UNIT> <COUNTRY> Canada</COUNTRY> <RATE> 3.0254</RATE> <CHANGE> -0.228</CHANGE> </CURRENCY> <CURRENCY> <NAME> krone</NAME> <UNIT> 1</UNIT> <COUNTRY> Denmark</COUNTRY> <RATE> 0.6219</RATE> <CHANGE> -0.209</CHANGE> </CURRENCY> <CURRENCY> <NAME> krone</NAME> <UNIT> 1</UNIT> <COUNTRY> Norway</COUNTRY> <RATE> 0.6248</RATE> <CHANGE> 0.016</CHANGE> </CURRENCY> <CURRENCY> <NAME> rand</NAME> <UNIT> 1</UNIT> <COUNTRY> South Africa</COUNTRY> <RATE> 0.4621</RATE> <CHANGE> 0.304</CHANGE> </CURRENCY> <CURRENCY> <NAME> krona</NAME> <UNIT> 1</UNIT> <COUNTRY> Sweden</COUNTRY> <RATE> 0.5093</RATE> <CHANGE> 0.118</CHANGE> </CURRENCY> <CURRENCY> <NAME> franc</NAME> <UNIT> 1</UNIT> <COUNTRY> Switzerland</COUNTRY> <RATE> 3.1438</RATE> <CHANGE> -0.314</CHANGE> </CURRENCY> <CURRENCY> <NAME> dinar</NAME> <UNIT> 1</UNIT> <COUNTRY> Jordan</COUNTRY> <RATE> 6.6869</RATE> <CHANGE> -0.356</CHANGE> </CURRENCY> <CURRENCY> <NAME> pound</NAME> <UNIT> 10</UNIT> <COUNTRY> Lebanon</COUNTRY> <RATE> 0.0314</RATE> <CHANGE> -0.317</CHANGE> </CURRENCY> <CURRENCY> <NAME> pound</NAME> <UNIT> 1</UNIT> <COUNTRY> Egypt</COUNTRY> <RATE> 1.0243</RATE> <CHANGE> -0.088</CHANGE> </CURRENCY> </CURRENCIES> <!--- End of Sample XML file ---> Sample XSL file: ==================== <?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:template match="CURRENCIES"> <xsl:for-each select="CURRENCY"> <xsl:apply-templates select="." /> </xsl:for-each> </xsl:template> <xsl:template match="CURRENCY"> <xsl:variable name="dt" select="/CURRENCIES/LAST_UPDATE"/> <xsl:value-of select="concat(substring($dt,1,4), substring($dt,6,2), substring($dt,9,2))"/> <xsl:text> , </xsl:text> <xsl:value-of select="NAME"/> <xsl:text> , </xsl:text> <xsl:value-of select="UNIT"/> <xsl:text> , </xsl:text> <xsl:value-of select="COUNTRY"/> <xsl:text> , </xsl:text> <xsl:value-of select="RATE"/> <xsl:text> , </xsl:text> <xsl:value-of select="CHANGE"/> <xsl:text> </xsl:text> </xsl:template> </xsl:stylesheet> < !--- End of sample XSL ----->
This was first published in October 2002