This post shows how to generate PDF from XML in Java using Apache FOP.
Apache FOP
Apache™ FOP (Formatting Objects Processor) is a print formatter driven by XSL formatting objects (XSL-FO) and an output independent formatter. It is a Java application that reads a formatting object (FO) tree and renders the resulting pages to a specified output. Output formats currently supported include PDF, PS, PCL, AFP, XML (area tree representation), Print, AWT and PNG, and to a lesser extent, RTF and TXT. The primary output target is PDF.
Maven dependency for Apache FOP
To get the Apache FOP related jars in your application’s classpath you need to add following dependency in the pom.xml file.
<dependency> <groupId>org.apache.xmlgraphics</groupId> <artifactId>fop</artifactId> <version>2.3</version> <exclusions> <exclusion> <groupId>xml-apis</groupId> <artifactId>xml-apis</artifactId> </exclusion> </exclusions> </dependency>
Note that java.xml package in xml-apis was conflicting with the java.xml package in JDK 10 that’s why it is excluded.
Alternatively you can download Apache FOP from here- https://xmlgraphics.apache.org/fop/download.html and copy the required jars yourself.
Steps to create PDF from XML using Apache FOP
- First you need to transform your XML file to XSL-FO using XSLT.
- Then using FOP you transform the XSL-FO to PDF.
Creating PDF from XML in Java using Apache FOP – Hello World example
First let’s create a hello world PDF from XML using Apache FOP and Java which just shows the passed name in the PDF.
XML used for this example is a very simple one having just one element name.
name.xml<?xml version="1.0" encoding="UTF-8"?> <name>knpcode</name>
You also need a style sheet which is used to transform the XML to XSL-FO.
style.xsl<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format"> <xsl:template match="/"> <fo:root> <fo:layout-master-set> <fo:simple-page-master master-name="simpleA4" page-height="29.7cm" page-width="21.0cm" margin="2cm"> <fo:region-body/> </fo:simple-page-master> </fo:layout-master-set> <fo:page-sequence master-reference="simpleA4"> <fo:flow flow-name="xsl-region-body"> <fo:block font-family="Helvetica" color="red" font-size="16pt" font-weight="bold"> Hello, <xsl:value-of select="name"/>! </fo:block> </fo:flow> </fo:page-sequence> </fo:root> </xsl:template> </xsl:stylesheet>
Few things to note in this XSL are-
- Namespace for fo is added in the XSL- xmlns:fo="http://www.w3.org/1999/XSL/Format"
- Here matching is done using “/” root itself.
- The value of the name element is extracted from the XML, there are also font and text color settings.
Java program that does the transformation from XML to XSL-FO and from XSL-FO to PDF.
import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import javax.xml.transform.Result; import javax.xml.transform.Source; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.sax.SAXResult; import javax.xml.transform.stream.StreamSource; import org.apache.fop.apps.FOPException; import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.Fop; import org.apache.fop.apps.FopFactory; import org.apache.fop.apps.MimeConstants; public class PDFFromFOP { public static void main(String[] args) { try { File xmlfile = new File("resources\\name.xml"); File xsltfile = new File("resources\\style.xsl"); File pdfDir = new File("./Test"); pdfDir.mkdirs(); File pdfFile = new File(pdfDir, "hello.pdf"); System.out.println(pdfFile.getAbsolutePath()); // configure fopFactory as desired final FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI()); FOUserAgent foUserAgent = fopFactory.newFOUserAgent(); // configure foUserAgent as desired // Setup output OutputStream out = new FileOutputStream(pdfFile); out = new java.io.BufferedOutputStream(out); try { // Construct fop with desired output format Fop fop; fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent, out); // Setup XSLT TransformerFactory factory = TransformerFactory.newInstance(); Transformer transformer = factory.newTransformer(new StreamSource(xsltfile)); // Setup input for XSLT transformation Source src = new StreamSource(xmlfile); // Resulting SAX events (the generated FO) must be piped through to FOP Result res = new SAXResult(fop.getDefaultHandler()); // Start XSLT transformation and FOP processing transformer.transform(src, res); } catch (FOPException | TransformerException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { out.close(); } }catch(IOException exp){ exp.printStackTrace(); } } }Created PDF
Creating PDF from XML using Apache FOP – PDF table example
Here is another Java example where data from the XML is shown as a table in PDF. In the XSL you need to specify the matching element and the program loops through that element to create one row in the table for each repetition of the matched element.
organization.xml<?xml version="1.0" encoding="UTF-8"?> <organization> <orgname>XYZ Pvt. Ltd.</orgname> <branch> <name>XYZ software services</name> <city>Bangalore</city> <startdate>12/05/2002</startdate> </branch> <branch> <name>XYZ financial services</name> <city>New York City</city> <startdate>10/04/1975</startdate> </branch> <branch> <name>XYZ hardware services</name> <city>Taipei</city> <startdate>20/10/2004</startdate> </branch> </organization>
In the PDF we need one row per branch element and show data for the child elements with in that row.
organization.xsl<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format"> <!-- Attribute used for table border --> <xsl:attribute-set name="tableBorder"> <xsl:attribute name="border">solid 0.1mm black</xsl:attribute> </xsl:attribute-set> <xsl:template match="organization"> <fo:root> <fo:layout-master-set> <fo:simple-page-master master-name="simpleA4" page-height="29.7cm" page-width="21.0cm" margin="1cm"> <fo:region-body/> </fo:simple-page-master> </fo:layout-master-set> <fo:page-sequence master-reference="simpleA4"> <fo:flow flow-name="xsl-region-body"> <fo:block font-size="16pt" font-family="Helvetica" color="blue" font-weight="bold" space-after="5mm"> Organization Name: <xsl:value-of select="orgname"/> </fo:block> <fo:block font-size="10pt"> <fo:table table-layout="fixed" width="100%" border-collapse="separate"> <fo:table-column column-width="5cm"/> <fo:table-column column-width="5cm"/> <fo:table-column column-width="5cm"/> <fo:table-header> <fo:table-cell xsl:use-attribute-sets="tableBorder"> <fo:block font-weight="bold">Name</fo:block> </fo:table-cell> <fo:table-cell xsl:use-attribute-sets="tableBorder"> <fo:block font-weight="bold">City</fo:block> </fo:table-cell> <fo:table-cell xsl:use-attribute-sets="tableBorder"> <fo:block font-weight="bold">Start Date</fo:block> </fo:table-cell> </fo:table-header> <fo:table-body> <xsl:apply-templates select="branch"/> </fo:table-body> </fo:table> </fo:block> </fo:flow> </fo:page-sequence> </fo:root> </xsl:template> <xsl:template match="branch"> <fo:table-row> <fo:table-cell xsl:use-attribute-sets="tableBorder"> <fo:block> <xsl:value-of select="name"/> </fo:block> </fo:table-cell> <fo:table-cell xsl:use-attribute-sets="tableBorder"> <fo:block> <xsl:value-of select="city"/> </fo:block> </fo:table-cell> <fo:table-cell xsl:use-attribute-sets="tableBorder"> <fo:block> <xsl:value-of select="startdate"/> </fo:block> </fo:table-cell> </fo:table-row> </xsl:template> </xsl:stylesheet>
In the XSL you can see initial matching is for the root element “organization” then again there is template matching for element "branch". For <branch> element value of the child elements are extracted and displayed with in the table cells in PDF.
Java program that do the transformation from XML to XSL-FO and from XSL-FO to PDF.
public class PDFFromFOP { public static void main(String[] args) { try { File xmlfile = new File("resources\\organization.xml"); File xsltfile = new File("resources\\organization.xsl"); File pdfDir = new File("./Test"); pdfDir.mkdirs(); File pdfFile = new File(pdfDir, "organization.pdf"); System.out.println(pdfFile.getAbsolutePath()); // configure fopFactory as desired final FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI()); FOUserAgent foUserAgent = fopFactory.newFOUserAgent(); // configure foUserAgent as desired // Setup output OutputStream out = new FileOutputStream(pdfFile); out = new java.io.BufferedOutputStream(out); try { // Construct fop with desired output format Fop fop; fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent, out); // Setup XSLT TransformerFactory factory = TransformerFactory.newInstance(); Transformer transformer = factory.newTransformer(new StreamSource(xsltfile)); // Setup input for XSLT transformation Source src = new StreamSource(xmlfile); // Resulting SAX events (the generated FO) must be piped through to FOP Result res = new SAXResult(fop.getDefaultHandler()); // Start XSLT transformation and FOP processing transformer.transform(src, res); } catch (FOPException | TransformerException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { out.close(); } }catch(IOException exp){ exp.printStackTrace(); } } }created PDF
Creating PDF from XML using Apache FOP – In web application
If you want to render the generated PDF on the browser in your web application then you can use something similar to as given below-
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try{ FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI()); //Setup a buffer to obtain the content length ByteArrayOutputStream out = new ByteArrayOutputStream(); //Setup FOP Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, out); TransformerFactory factory = TransformerFactory.newInstance(); Transformer transformer = factory.newTransformer(new StreamSource(PATH_TO_XSL)); //Make sure the XSL transformation's result is piped through to FOP Result res = new SAXResult(fop.getDefaultHandler()); //Setup input Source src = new StreamSource(new File("PATH_TO_XML")); //Start the transformation and rendering process transformer.transform(src, res); //Prepare response response.setContentType("application/pdf"); response.setContentLength(out.size()); //Send content to Browser response.getOutputStream().write(out.toByteArray()); response.getOutputStream().flush(); }catch(Exception e){ e.printStackTrace(); } }
That's all for the topic Generate PDF From XML in Java Using Apache FOP. If something is missing or you have something to share about the topic please write a comment.
You may also like
- Generating PDF in Java Using iText Tutorial
- Generating PDF in Java Using OpenPDF Tutorial
- GZIP Multiple Files in Java Creating Tar Archive
- Getting Current Date and Time in Java
- ReentrantLock in Java With Examples
- Java StringJoiner Class With Method Examples
- Interface Vs Abstract Class in Java
- Inheritance in Python With Examples
No comments:
Post a Comment