Creating the publishcat Application
Now that we have explained all of the supporting files, we can discuss the publishcat application itself. It uses the C SAX parser to read the XSLConfig.xml file and the DOM parser to prepare the input document for stylesheet transformation that is done with the XSLT processor.
This section declares the header files and sets up a global structure to hold the profile parameters that will be retrieved from the configuration file:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#ifndef XML_ORACLE
# include <xml.h>
#endif
typedef struct {
xmlctx *xctx;
oratext *sskeyword;
size_t sskeylen;
oratext *elem;
oratext characterset[80];
oratext outputfile[80];
oratext graphics[80];
oratext colordepth[80];
oratext stylesheets[80];
oratext profiles[80];
} saxctx;
The findsub() support function is used to handle the SAX character events that we are not interested in:
/*––––––––––––––––––––––––––––––––––––––––––––––––––
support functions
––––––––––––––––––––––––––––––––––––––––––––––––––*/
static oratext *findsub(oratext *buf, size_t bufsiz,
oratext *sub, size_t subsiz)
{
uword i;
if (!buf || !bufsiz || (subsiz > bufsiz))
return NULL;
if (!sub || !subsiz)
return buf;
for (i = 0; i < bufsiz - subsiz; i++, buf++)
{
if (!memcmp(buf, sub, subsiz))
return buf;
}
return NULL;
}
The following is the SAX callback section in which you declare the content handlers for the SAX event stream. Note that you need to handle expected content types, which in this case are startDocument, endDocument, startElement, endElement, and characters.
/* ––––––––––––––––––––––––––––––––––––––––––
SAX callbacks
–––––––––––––––––––––––––––––––––-–––––––––*/
static XMLSAX_START_DOC_F(startDocument, ctx)
{
return 0;
}
static XMLSAX_END_DOC_F(endDocument, ctx)
{
return 0;
}
static XMLSAX_START_ELEM_F(startElement, ctx, name, attrs)
{
((saxctx *) ctx)->elem = name;
return 0;
}
static XMLSAX_END_ELEM_F(endElement, ctx, name)
{
((saxctx *) ctx)->elem = (oratext *) ";
return 0;
}
static XMLSAX_CHARACTERS_F(characters, ctx, ch, len)
{
saxctx *sc = (saxctx *) ctx;
if (!strcmp((char *) sc->elem, "Stylesheets"))
{
memcpy(sc->stylesheets, ch, len); /* set current ss */
sc->stylesheets[len] = 0;
}
else if (!strcmp((char *)sc->elem, "Profiles"))
{
memcpy(sc->profiles, ch, len); /* set current profiles */
sc->profiles[len] = 0;
}
else if (!strcmp((char *)sc->elem, "CharacterSet"))
{
memcpy(sc->characterset, ch, len);
sc->characterset[len] = 0;
}
else if (!strcmp((char *)sc->elem, "OutputFileType"))
{
memcpy(sc->outputfile, ch, len);
sc->outputfile[len] = 0;
}
else if (!strcmp((char *)sc->elem, "Graphics"))
{
memcpy(sc->graphics, ch, len);
sc->graphics[len] = 0;
}
else if (!strcmp((char *)sc->elem, "ColorDepth"))
{
memcpy(sc->colordepth, ch, len);
sc->colordepth[len] = 0;
}
else if (!strcmp((char *)sc->elem, "LinesPerPage"))
{
memcpy(sc->linesperpage, ch, len);
sc->linesperpage[len] = 0;
}
else if (findsub((oratext *) ch, len, sc->sskeyword, sc->sskeylen))
return 0;
}
static xmlsaxcb saxcb = {
startDocument,
endDocument,
startElement,
endElement,
characters
};
The following is the main function of publishcat that initially processes the command-line parameters by assigning them to variables. The code is commented to describe its flow.
/*–––––––––––––-Main function ––––––––––––––-*/
int main(int argc, char *argv[])
{
xmlctx *xctx = NULL;
xslctx *xslx = NULL;
saxctx sc;
xmlerr err;
oratext *xmlfile, *outfile, *xslconfigFile, *xslfile, *schemaURL;
xmldocnode *doc = NULL, *ss_doc = NULL;
if (argc < 4) {
printf("\nUsage error: publishcat -h -i<inputXML> -o<outputFile>
-p<XSLConfig.xml>\n\n - h show commandline and
parameters \n\n - i input XML \n\n - o output file
(extension optional as it will use default
for format)\n\n - p profile (defined in XSLConfig.xml)\n\n");
return 0;
}
xmlfile = (oratext *)argv[2];
xmlfile = xmlfile+2;
outfile = (oratext *)argv[3];
outfile = outfile+2;
xslconfigFile = (oratext *)argv[4];
xslconfigFile = xslconfigFile + 2;
/* Creates the context */
if (!(xctx = XmlCreate(&err, (oratext *)"xslsample_xctx", NULL)))
{
printf("Failed to create XML context, error %u\n", (unsigned)err);
goto terminate;
}
/* Creates the DOM and parses */
if (!(doc=XmlLoadDom(xctx, &err, "file", xmlfile,
"validate", TRUE, "discard_whitespace", TRUE, NULL)))
{
printf("Parse failed, code %d\n", (int)err);
goto terminate;
}
/* Retrieves Schema URL from DOM */
schemaURL = XmlDomGetSchema(xctx, doc);
/* Init SAX context */
memset(&sc, sizeof(sc), 0);
sc.sskeyword = (oratext *)"xsl";
sc.sskeylen = strlen(sc.sskeyword);
sc.elem = (oratext *) ";
/* Parse XSLConfig.xml using SAX */
if (!(err=XmlLoadSax(xctx, &saxcb, &sc, "file", xslconfigFile,
"validate", TRUE, "discard_whitespace", TRUE, NULL)))
{
printf("Parse failed, code %d\n", (int)err);
goto terminate;
}
/* Retrieves XSL stylesheet using SAX and profile parameters */
xslfile = sc.stylesheets;
/* Parsing stylesheet */
if (!(ss_doc = XmlLoadDom(xctx, &err, "file", xslfile,
"validate", TRUE, "discard_whitespace", TRUE, NULL)))
{
printf("Parse failed, error %u\n", (unsigned)err);
goto terminate;
}
/* Initialize the result context */
xslx = XmlXslCreate(xctx, ss_doc, xslfile, &err);
/* Set Profile Parameters */
if (err=XmlXslSetTextParam(xslx, (oratext *)"CharacterSet",
sc.characterset))
{
printf("Setting failed, error %u\n", (unsigned)err);
}
if (err=XmlXslSetTextParam(xslx, (oratext *)"OutputFileType",
sc.outputfile))
{
printf("Setting failed, error %u\n", (unsigned)err);
}
if (err=XmlXslSetTextParam(xslx, (oratext *)"Graphics", sc.graphics))
{
printf("Setting failed, error %u\n", (unsigned)err);
}
if (err=XmlXslSetTextParam(xslx, (oratext *)"ColorDepth",
sc.colordepth))
{
printf("Setting failed, error %u\n", (unsigned)err);
}
if (err=XmlXslSetTextParam(xslx, (oratext *)"LinesPerPage",
sc.linesperpage))
{
printf("Setting failed, error %u\n", (unsigned)err);
}
/* XSL processing */
if (err = XmlXslProcess(xslx, doc, FALSE))
{
printf("Processing failed, error %u\n", (unsigned)err);
goto terminate;
}
/* Serialize result to specified output file */
XmlSaveDom(xctx, &err, doc, "outFile", NULL);
/* Clean up and terminate contexts */
terminate:
if (doc)
XmlFreeDocument(xctx, doc);
if (ss_doc)
XmlFreeDocument(xctx, ss_doc);
if (xctx)
XmlDestroy(xctx);
if (xslx)
XmlXslDestroy(xslx);
return 1;
}
The following is an example command line for execution:
publishcat -i dvdlist.xml -o dvdlistl -p XSLConfig.xml