Search code examples
javaxsltpdfapache-fop

One FOP XSLT transformation but different files rendered


Is there any way to make only one xslt transformation and render the output to pdf, png, svg files?

StreamSource contentSource = new StreamSource(xmlContentStream);
StreamSource transformSource = new StreamSource(xslFoMarkupStream);

ByteArrayOutputStream outStream = new ByteArrayOutputStream();

Transformer xslfoTransformer = getTransformer(transformSource);

Fop fop = fopFactory.newFop("application/pdf", foUserAgent, outStream);

Result res = new SAXResult(fop.getDefaultHandler());

// Start XSLT transformation and FOP processing
xslfoTransformer.transform(contentSource, res);

xmlContentStream.close();
xslMarkupStream.close();
return outStream;

In the case above to generate PDF and then PNG I will have to create a new Fop instance with different mime type and then again call xslfoTransformer.transform().

That means that I will have the transformation twice, but I wonder if there is a way to run the transformation once and then render the output to different formats? (Custom Renderer?)

Or maybe there are any suggestions to speed up the rendering as I still need to do it several times - once for PDF, PNG, SVG.

I also tried to generate PDF via FOP and then convert it to image via Apache PdfBox. That works slightly faster, but looks silly.

Thank_you.


Solution

  • You can save one step. Your code does 2 steps above: take some arbitrary XML, transform that into XSL:FO using XSLT and then render the output into whatever format you want. You could do the transformation XML to XSL:FO (probably the slower part) once and use that result as input to 2 FO instances. Something like this:

        public void fopReport(OutputStream pdfOut, OutputStream jpgOut, Source xmlSource, Source xsltSource) throws Exception {
                // Create the FO content
                TransformerFactory factory = TransformerFactory.newInstance();
                Transformer transformer = factory.newTransformer(xsltSource);
                ByteArrayOutputStream foBytesStream = new ByteArrayOutputStream();
                StreamResult foByteStreamResult = new StreamResult(foBytesStream);
                transformer.transform(xmlSource, foByteStreamResult);
                byte[] foBytes = foBytesStream.toByteArray();
    
                // Render twice
                FopFactory fopFactory = FopFactory.newInstance();
                FOUserAgent uaPDF = fopFactory.newFOUserAgent();
                FOUserAgent uaJpg = fopFactory.newFOUserAgent();
    
                Fop fopPDF = fopFactory.newFop(MimeConstants.MIME_PDF, uaPDF, pdfOut);
                Fop fopJpg = fopFactory.newFop(MimeConstants.MIME_JPEG, uaJpg, jpgOut);
    
                //PDF
                Source src = new StreamSource(new ByteArrayInputStream(foBytes));
                Transformer resultTransformer = factory.newTransformer();
                resultTransformer.transform(src, new SAXResult(fopPDF.getDefaultHandler()));
    
                //JPF
                src = new StreamSource(new ByteArrayInputStream(foBytes));
                resultTransformer = factory.newTransformer();
                resultTransformer.transform(src, new SAXResult(fopJpg.getDefaultHandler()));
            }
    

    Hope that helps