0

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.

Eugene S
  • 99
  • 1
  • 11

1 Answers1

0

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

stwissel
  • 20,110
  • 6
  • 54
  • 101
  • I'm sorry, my code a little bit hazy. What I'm doing is just applying xsl-fo markup to the xml and render output to pdf. There is no xml to xsl-fo transformation. – Eugene S Apr 30 '14 at 07:01
  • Eugene, the "applying xsl-fo markup to XML" in your code *is* an xslt transformation. It is chained to the xsl-fo to final format (PDF) step. If you have multiple target formats you break that chain and do the first part only once. – stwissel Apr 30 '14 at 07:18
  • Ok, now I see what you mean, thank you! I also found the Apache FOP intermediate format feature http://xmlgraphics.apache.org/fop/1.1/intermediate.html (the IF one) it seems the case for me. It renders IF file and then render anything you want from that IF file. – Eugene S Apr 30 '14 at 09:09
  • Glad to be of service. Feel free to accept the answer – stwissel Apr 30 '14 at 10:47