- Andrew Kos
- Bill Burlein
- Bryan Williams
- Christian Vozar
- Jeff Brown
- John Kraus
- Joseph Mak
- Mark Daugherty
- Matt Van Bergen
- Melissa Geoffrion
- Michael Kang
- Michael Chan
- Michael Hodgdon
- Mike Motherway
- Molly McDaniel
- Nadia Maciulis
- Pat McLoughlin
- Paul Michelotti
- Puru Hemnani
- Rohit Srinath
- Ryan Lunka
- Tom Kelly
All Blogs
CITYTECH Blogroll:
Using Apache FOP to generate a PDF document based on a form submission data
Friday, February 15, 2013
Need to generate a PDF document based on a form submission data? Apache FOP can do just that!
Recently, I was working on a CQ component that contained a form that based on the user input, generated a PDF document. The requirements called for three types of PDF documents (a certificate of sorts). The data entered by the user was being used to determine the type of document issued. All three types of documents had a similar layout, but the copy was different and each document contained user-specific values coming from the form and subsequent calculations.
So the scenario is fairly standard, albeit not straightforward.
How do you go about solving this problem and implementing a solution?
Step 1: determine the tool
Step 2: determine the process
Step 3: try it out i.e. code
1) The perfect tool for this was Apache FOP (Formatting Objects Processor). Not only was it designed to transform structured text into formatted output, but it comes bundled with CQ (the Apache FOP bundle: com.day.commons.osgi.wrapper.fop). My client was using CQ5.4, so the version of FOP is quite ancient, but it was enough for the task at hand.
2) Since my three PDF documents had similar layouts and the differences laid mainly in the content, I chose to have just one style sheet (XSL file) and three XML content files - one for each type of document. The xml files contained placeholders for dynamic values: ${name}, ${address}, ${company}, ${certificationScore}, ${instrumentType}, etc.
I have the XSL and XML files bundled with the application jar. For multilingual version of the site, the XML files would have to be translated into all languages available on the site. Alternatively, the content could be defined in a component for easy updates.
Samples of style sheet and the content files: certificate.xsl, certificate1.xml, certificate2.xml.
3) The servlet tied to the form did the following:
- Form validation
- All necessary calculations to determine output i.e. which type of document to generate
- Actual PDF generation:
- Define FopFactory and TransformerFactory
private static final FopFactory FOP_FACTORY = FopFactory.newInstance(); private static final TransformerFactory T_FACTORY = TransformerFactory.newInstance();
- Setup output stream – if you want to save the file on disk, it will be FileOutputStream, otherwise ByteArrayOutputStream
ByteArrayOutputStream out = new ByteArrayOutputStream(); //or alternatively: //OutputStream out = new FileOutputStream(outputFile);
- Create a map with replacement values, get the appropriate XML file and replace all markers with the replacement values, setup FOP objects, set parameters used in the XSL style sheet, and transform the source into output
// get the xml file and replace all markers (not all shown here)
InputStream in = getClass().getResourceAsStream("META-INF/certificate1.xml");
String contentStr = IOUtils.toString(in, "UTF-8");
...
//Setup FOP
Fop fop = FOP_FACTORY.newFop("application/pdf", out);
//Setup Transformer
Source xsltSrc = new StreamSource(getClass().getResourceAsStream("META-INF/certificate.xsl"));
Transformer transformer = T_FACTORY.newTransformer(xsltSrc);
//Make sure the XSL transformation's result is piped through to FOP
Result result = new SAXResult(fop.getDefaultHandler());
transformer.setParameter("instrumentInfo", "yes");
transformer.setParameter("companyInfo", "no");
transformer.setParameter("displaySeal", "yes");
transformer.setParameter("imagePath", imagePath);
...
//Start the transformation and rendering process
transformer.transform(new StreamSource(new StringReader(contentStr)), result);
LOG.debug("generated pdf has {} pages", fop.getResults().getPageCount());
- Set the output as servlet content (or alternatively save to disk, email, save to DAM)
//Prepare response
response.setContentType("application/pdf");
response.setContentLength(out.size());
//Send content to Browser
response.getOutputStream().write(out.toByteArray());
response.getOutputStream().flush();
With those few steps and some knowledge of XSL you can have your website generate PDF documents!
Celina Buczkowska
Celina has over seven years of experience in the full lifecycle of application development, concentrating on design and implementation. She has a strong background i...
Recent Posts
- Invisible requirements within Business requirements
- Building a better Options Predicate
- Javascript, This, and You.
- Extensionless URLs with Adobe Experience Manager
- The Life of a Tester in Adobe CQ World!
- Limitations of the CQ Parsys Model and the Implementation of a Nested Paragraph System
- Google Analytics and AEM: No JavaScript? No Problem.
- Using Apache FOP to generate a PDF document based on a form submission data
- Configuring SAML in AEM 5.6
- Why You Should Get the WCM Experts Involved Early