Creating a PDF file from an XML file using XSLT and XSL-FO!

And Apache FOP, of course!!!

source.xml
<?xml version="1.0" encoding="UTF-8"?>
<catalog>
    <cd>
        <title>Empire Burlesque</title>
        <artist>Bob Dylan</artist>
        <country>USA</country>
        <company>Columbia</company>
        <price>10.90</price>
        <year>1985</year>
    </cd>
    <cd>
        <title>Hide your heart</title>
        <artist>Bonnie Tyler</artist>
        <country>UK</country>
        <company>CBS Records</company>
        <price>9.90</price>
        <year>1988</year>
    </cd>
</catalog>

fop.xconf
<?xml version="1.0"?>
<fop version="1.0">
    <!-- Base URL for resolving relative URLs -->
    <base>.</base>
    <source-resolution>72</source-resolution>
    <target-resolution>72</target-resolution>
    <default-page-settings height="297mm" width="210mm"/>
    <renderers>
        <renderer mime="application/pdf">
            <filterList>
                <value>flate</value>
            </filterList>
            <fonts>
                <auto-detect/>
            </fonts>
        </renderer>
    </renderers>
</fop>

style.xsl
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:fo="http://www.w3.org/1999/XSL/Format" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xsi:schemaLocation="http://www.w3.org/1999/XSL/Transform                                     
                        https://www.w3.org/2007/schema-for-xslt20.xsd                                     
                        http://www.w3.org/1999/XSL/Format                                     
                        https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk/fop/src/foschema/fop.xsd">
    <xsl:template match="/">
        <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
            <fo:layout-master-set>
                <fo:simple-page-master margin-bottom="2cm" 
                                       margin-left="2.5cm" 
                                       margin-right="2.5cm" 
                                       margin-top="1cm" 
                                       master-name="simple" 
                                       page-height="297mm" 
                                       page-width="210mm">
                    <fo:region-body margin-top="3cm"/>
                    <fo:region-before extent="3cm"/>
                    <fo:region-after extent="1.5cm"/>
                </fo:simple-page-master>
            </fo:layout-master-set>
            <fo:page-sequence master-reference="simple">
                <fo:flow flow-name="xsl-region-body">
                    <xsl:for-each select="catalog/cd">
                        <fo:block>
                            <fo:inline font-weight="bold">
                                <xsl:value-of select="artist"/>
                            </fo:inline>
                             - 
                             <xsl:value-of select="title"/>
                         </fo:block>
                    </xsl:for-each>
                    <fo:block>
                        <fo:external-graphic src="/Users/koraytugay/Desktop/truck.jpg"/>
                    </fo:block>
                </fo:flow>
            </fo:page-sequence>
        </fo:root>
    </xsl:template>
</xsl:stylesheet>

FopHelloWorld.java
import org.apache.fop.apps.Fop;
import org.apache.fop.apps.FopFactory;
import org.apache.fop.apps.MimeConstants;
import org.xml.sax.SAXException;
 
import javax.xml.transform.*;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import java.io.*;
 
/* User: koray@tugay.biz Date: 2016/07/27 */
public class FopHelloWorld {
 
    public static void main(String[] args) throws IOException, SAXException, TransformerException {
        final StreamSource style = new StreamSource("/Users/koraytugay/Desktop/examples/style.xsl");
        final StreamSource data = new StreamSource("/Users/koraytugay/Desktop/examples/source.xml");
        final TransformerFactory transformerFactory = TransformerFactory.newInstance();
        Transformer transformer = transformerFactory.newTransformer(style);
        final String resultPath = "/Users/koraytugay/Desktop/examples/result.xml";
        final FileOutputStream stream = new FileOutputStream(resultPath);
        final StreamResult outputTarget = new StreamResult(stream);
        transformer.transform(data, outputTarget);
        ////////////////////
        TransformerFactory factory = TransformerFactory.newInstance();
        transformer = factory.newTransformer(); // identity transformer
        Source src = new StreamSource(new File(resultPath));
        final File fopConf = new File("/Users/koraytugay/Desktop/examples/fop.xconf");
        final FopFactory fopFactory = FopFactory.newInstance(fopConf);
        final File pdfFile = new File("/Users/koraytugay/Desktop/examples/cds.pdf");
        final FileOutputStream pdfFileOutputStream = new FileOutputStream(pdfFile);
        final OutputStream out = new BufferedOutputStream(pdfFileOutputStream);
        final Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, out);
        Result res = new SAXResult(fop.getDefaultHandler());
        transformer.transform(src, res);
        out.close();
    }
}

And the resulting pdf will look something like this:
which is quite nice, right? The example we have first creates a file called result.xml after processing the XSL Transformation, and then Apache FOP does its magic on this file. Lets see what result.xml looks like:
<?xml version="1.0" encoding="UTF-8"?>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <fo:layout-master-set>
        <fo:simple-page-master margin-bottom="2cm" 
                               margin-left="2.5cm" 
                               margin-right="2.5cm" 
                               margin-top="1cm" 
                               master-name="simple" 
                               page-height="297mm" 
                               page-width="210mm">
            <fo:region-body margin-top="3cm"/>
            <fo:region-before extent="3cm"/>
            <fo:region-after extent="1.5cm"/>
        </fo:simple-page-master>
    </fo:layout-master-set>
    <fo:page-sequence master-reference="simple">
        <fo:flow flow-name="xsl-region-body">
            <fo:block>
                <fo:inline font-weight="bold">
                    Bob Dylan
                </fo:inline>
                - Empire Burlesque
            </fo:block>
            <fo:block>
                <fo:inline font-weight="bold">
                    Bonnie Tyler
                </fo:inline>
                - Hide your heart
            </fo:block>
            <fo:block>
                <fo:external-graphic src="/Users/koraytugay/Desktop/truck.jpg"/>
            </fo:block>
        </fo:flow>
    </fo:page-sequence>
</fo:root>

So lets say we do not want this result.xml file.. How to avoid it? Here it is:
import org.apache.fop.apps.Fop;
import org.apache.fop.apps.FopFactory;
import org.apache.fop.apps.MimeConstants;
import org.xml.sax.SAXException;
 
import javax.xml.transform.*;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import java.io.*;
 
/* User: koray@tugay.biz Date: 2016/07/27 */
public class FopHelloWorld {
 
    public static void main(String[] args) throws IOException, SAXException, TransformerException {
        final StreamSource style = 
                new StreamSource("/Users/koraytugay/Desktop/examples/style.xsl");
        final StreamSource data = 
                new StreamSource("/Users/koraytugay/Desktop/examples/source.xml");
        final TransformerFactory transformerFactory = TransformerFactory.newInstance();
        Transformer transformer = transformerFactory.newTransformer(style);
        final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        final StreamResult outputTarget = new StreamResult(byteArrayOutputStream);
        transformer.transform(data, outputTarget);
        final byte[] bytes = byteArrayOutputStream.toByteArray();
        ////////////////////
        TransformerFactory factory = TransformerFactory.newInstance();
        transformer = factory.newTransformer(); // identity transformer
        Source src = new StreamSource(new ByteArrayInputStream(bytes));
        final FopFactory fopFactory 
                = FopFactory.newInstance(
                new File("/Users/koraytugay/Desktop/examples/fop.xconf"));
        final OutputStream out = 
                new BufferedOutputStream(
                        new FileOutputStream(
                                new File("/Users/koraytugay/Desktop/examples/cds.pdf")));
        final Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, out);
        Result res = new SAXResult(fop.getDefaultHandler());
        transformer.transform(src, res);
        out.close();
    }
}

The output will be exactly same, only difference is result.xml will not be stored in the disk. So we have source.xml, we will do xsl transformation on it and keep it in memory and feed this transformed data to xsl-fo.. So no result.xml.

Resources: 1, 2, 3, 4