Generating the PDF Files

page 183 When we invoke the PDF-generating templates with the mode=generate-pdf attribute, we pass in the page-size parameter to set the dimensions of the printed page. We generate PDFs with both letter-sized and A4-sized pages to support our customers around the world. To create the PDF, we first create the output file of formatting objects, converting the various XML tags from our source document into the various formatting objects we need: fo:block font-size=16pt line-height=19pt font-weight=bold space-after.optimum=12pt Introduction to JavaServer Pages fo:block fo:block space-after.optimum=6pt In todays environment, most web sites want to display dynamic content based on the user and the session. Most content, such as images, text, and banner ads, is most easily built with HTML editors. So we need to mix the static content of HTML files with directives for accessing or generating dynamic content. fo:block fo:block space-after.optimum=6pt JavaServer Pages meet this need. They provide server-side scripting support for generating web pages with combined static and dynamic content. fo:block Currently, the XSL:FO specification is a candidate recommendation at the World Wide Web Consortium W3C. Because future changes are likely, we wont discuss the formatting objects themselves. It suffices to say that our stylesheet defines page layouts margins, running headers and footers, etc. and then creates a number of formatting objects inside those page layouts. The FOP tool handles the details of calculating line, page, and column breaks, page references, and hyperlinks. Once the file of formatting objects is created, we call an extension function to convert the formatting objects file into a PDF. Heres the exensions main code: public static void buildPDFFileString foFilename, String pdfFilename { try { XMLReader parser = XMLReader Class.forNameorg.apache.xerces.parsers.SAXParser .newInstance; Driver driver = new Driver; driver.setRendererorg.apache.fop.render.pdf.PDFRenderer, Version.getVersion; driver.addElementMappingorg.apache.fop.fo.StandardElementMapping; driver.addElementMappingorg.apache.fop.svg.SVGElementMapping; driver.addPropertyListorg.apache.fop.fo.StandardPropertyListMapping; driver.addPropertyListorg.apache.fop.svg.SVGPropertyListMapping; driver.setOutputStreamnew FileOutputStreampdfFilename; driver.buildFOTreeparser, new InputSourcefoFilename; driver.format; driver.render; } The code merely creates the FOP Driver object, sets its various properties, and then tells it to render the formatting objects in a PDF file. The main difficulty here is in determining how the various XML elements should be converted to formatting objects; once the conversion is done, we have a tool that generates high-quality printable output from our XML source files. Best of all, this code uses open source tools exclusively. page 184

9.5.7 Generating the JPEG Files

Another thing we need to produce for the tutorial is a series of JPEG files. To have precise control over the appearance of the titles in the tutorial, we create a JPEG file in which the title text is written in a particular font. We discussed this code in Chapter 8 , so we wont go over it here. Heres the first significant section of the build-graphics.xsl file: xsl:template match=tutorial mode=generate-graphics xsl:choose xsl:when test=function-availablejpeg:buildJPEGFile xsl:value-of select=jpeg:buildJPEGFiletitle, concatmaster, fileSep, masthead.jpg, concatcurDir, fileSep, imagemaster, fileSep, masthead.jpg, baseFont, 27, 5, 30, 0, 0, 0 xsl:when xsl:otherwise xsl:message terminate=yes Error JPEG library not available xsl:message xsl:otherwise xsl:choose The buildJPEGFile function takes several parameters, including the title text in the example, our XPath expression passes in the value of the title element, the name of the background JPEG file we load this file, draw the text on top of it, and then save the new JPEG, the name of the new JPEG file, the name of the font, and other details about the font size, the x- and y- coordinates where the text should start, and the color in which to draw it. Although neither this extension nor the stylesheet that calls it are rocket science, they save us a tremendous amount of time in the tutorial development process. Before we had the Toot-O- Matic, we had to ask our highly trained, highly talented, and highly overworked graphics staff to create these graphics for us; now we do it automatically and the graphics staff can focus their talents on more important things.

9.5.8 Generating the Zip File

Our last task is to generate a zip file that contains all the files needed to view the tutorial locally. This includes all HTML files, all standard graphics, all JPEGs we generate, and any graphics referenced in the XML source anything in an img tag. We call another Java extension to build the zip file. Determining which files should be loaded into the zip file relies heavily on our naming conventions. When we invoke the buildZipFile function, we pass in several arguments. The first three are the root filename, the directory to which we write the output files, and the file separator for this platform. The next argument is the tutorial node itself; the extension uses DOM functions to determine what files should be added to the zip file. The final argument is a node-set of all the things that reference graphics files in the XML source. That includes the img attribute of any tag and the src attribute of the img element. Heres what the function call looks like: xsl:template match=tutorial mode=generate-zip-file xsl:choose xsl:when test=function-availablezip:buildZipFile xsl:variable name=referencedGraphics select=.img|image-columnimg|imgsrc xsl:value-of select=zip:buildZipFilefn, curDir, fileSep, ., referencedGraphics xsl:when xsl:otherwise page 185 xsl:message terminate=yes Error Zip file library not available xsl:message xsl:otherwise xsl:choose xsl:template In the extension function code itself, we start by creating the ZipOutputStream itself: ZipOutputStream zipOut = new ZipOutputStreamnew FileOutputStreamcurrentDirectory + fileSeparator + baseFilename + .zip; Once weve created our ZipOutputStream , well see if theres a comment for the zip file in the zip-file-comment attribute of the tutorial element: Node currentNode = tutorialElement.nextNode; while currentNode = null { if currentNode.getLocalName.equalstutorial { ElementImpl currentElement = ElementImplcurrentNode; String zipFileComment = currentElement.getAttributezip-file-comment; if zipFileComment = null zipOut.setCommentzipFileComment; else { zipFileComment = currentElement.getAttributealt; if zipFileComment = null zipOut.setCommentzipFileComment; } With everything we do with the DOM nodes, well need to make sure we actually work with the appropriate nodes; thats why we use the function call getLocalName.equalstutorial . Once weve found the tutorial element, we can work with its children to figure out the names of all the HTML and JPEG files we need to add to the zip file. If the tutorial element has five section children, and the first section contains eleven panel s, then well need to write the files tootomatic-1-1.html through tootomatic-1-11.html to the zip file. This assumes that the base filename we use is tootomatic . Heres an excerpt from the code: int numKids = currentElement.getChildCount; int numSections = 0; for int i = 0; i numKids; i++ { Node currentChild = currentElement.getChildi; if currentChild.getLocalName.equalssection { ElementImpl currentChildElement = ElementImplcurrentChild fileToZip = new FilecurrentDirectory + fileSeparator + index + ++numSections + .html; fis = new FileInputStreamfileToZip; entry = new ZipEntrycurrentDirectory + fileSeparator + fileToZip.getName; if zipOut = null { zipOut.putNextEntryentry; whilebytes_read = fis.readbuffer = -1 zipOut.writebuffer, 0, bytes_read; } fis.close; int numGrandkids = currentChildElement.getChildCount; int numPanels = 0; for int j = 0; j numGrandkids; j++ {