Using SAP CPI “microservice” to make a XML to PDF converter

I had created a video some time ago on the topic of converting XML to PDF, it pop-ups as a video that gets a lot of views. But I’m not really sharing any code and just talking about using Apache FOP for the project.

I wanted to check out how it was to develop with the Figaf IRT Git addon to make it possible to run all your Groovy development and see how it helped. It did help quite a bit in the process.

If you want to get an explanation of the process and content then check out this video.

You can download the full iflow here SAP CPI iflow XMLtoPDF

Then you just need to send data to it via the ProcessDirect adapter with /xmltopdf

 

The source code for the conversion

def Message processData(Message message) {
    //Body 
       def body = message.getBody(String.class)
           try {
              // Step 1: Construct a FopFactory by specifying a reference to the configuration file
// (reuse if you plan to render multiple documents!)
              FopFactoryBuilder fopFactoryBuilder = new FopFactoryBuilder(new URI("."))
              FopFactory fopFactory = fopFactoryBuilder.build();

// Step 2: Set up output stream.
// Note: Using BufferedOutputStream for performance reasons (helpful with FileOutputStreams).
              OutputStream out = new ByteArrayOutputStream()
              // Step 3: Construct fop with desired output format
              Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, out);

              // Step 4: Setup JAXP using identity transformer
              TransformerFactory factory = TransformerFactory.newInstance();
              Transformer transformer = factory.newTransformer(); // identity transformer

              // Step 5: Setup input and output for XSLT transformation
              // Setup input stream
              Source src = new StreamSource(new ByteArrayInputStream(body.getBytes()));

              // Resulting SAX events (the generated FO) must be piped through to FOP
              Result res = new SAXResult(fop.getDefaultHandler());

              // Step 6: Start XSLT transformation and FOP processing
              transformer.transform(src, res);
              out.flush()
              message.setBody(out.toByteArray());
              message.setHeader("Content-Type","application/pdf");


       } finally {

       }

       return message;
}
s

 

The XML you send need to contain the styling for the document. You can therefore not just sent any document you need to convert it to Apache Fob format. XSL would be really useful. And example is the following.

<?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:output indent="yes"/>
    <!-- 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>

 

You can go nuts an create your own styling. If you want to use images you probably have to add them to a jar a then extract the file from it.