Note: This article has been used with the generous permission of the author, Laurent Kempé. This copy is a computer-translation of the original article on Laurent's site, TechHeadBrothers.com.
- Jason

Utility based on NFop by Laurent Kempé

Generation of file pdf with NET.

FOP (Formatting Objects Processor) is a tool for formatting of impression controlled by XSL. It is an application which reads a tree of objects of formatting and which generates the resulting pages in a given format. For the moment the formats of returned according to are supported: Pdf, PCL, PS, SVG, XML, Print, AWT, MIF and TXT. pdf being the format of predilection.

NFop is the bearing by Jason Pettys in Visual J # of the project Apache FOP on platform NET. NFop is available on the SourceForge site to the following address: http://sourceforge.net/projects/nfop.

In order to be able to use NFop you need of course Framework .NET and must at least have "Microsoft Visual J # NET Redistributable Package" which you can download here.

This article will show you how to create using NFop a document pdf on the basis of documents XML and XSL.

For this presentation I wrote the article using Word and I used a small utility creates in Java which names wh2fo (version 0.3.1) in order to generate file XML very easily and XSL allowing to generate file FOP. You can find this utility with the following address Web: http://wh2fo.sourceforge.net/

Method

In order to be able to create a file pdf using NFop there are two possibilities:

  1. Creation since a file FOP of a file pdf
  2. Transformation of a file XML using XSLT into an intermediate file FOP then generation of file pdf
In both cases we use NFop to generate file pdf.

For that we can create a method which accepts in entering parameter a character string containing instructions FOP and another string representing the way of file pdf to be saved.

using System;
using System.IO;
using System.Xml;
using System.Xml.Xsl;
using ApacheFop;


namespace Fop
{
    class Transformer
    {
        [STAThread]
        static void Main(string[] args)
        {
            if ( args.Length == 3 ) 
            {
                XmlDocument dataDoc = new XmlDocument();
                dataDoc.Load( args[0] );

                // Transformation du XML en FOP à l'aide de XSLT
                XslTransform xslt = new XslTransform();
                xslt.Load( args[1] );
                StringWriter fullFoDoc = new StringWriter();
                xslt.Transform(dataDoc.CreateNavigator(), null, fullFoDoc);

                //Transformation du FOP en PDF
                Transform( fullFoDoc.ToString(), args[2] );         
            }
            else if ( args.Length == 2 ) 
            {
                StreamReader sr = new StreamReader( args[0] );

                //Transformation du FOP en PDF
                Transform( sr.ReadToEnd(), args[1] );           
            }
            else
            {
                Console.WriteLine("Usage: fop.exe file.xml file.xsl file.pdf");
                Console.WriteLine("    or fop.exe file.fo file.pdf");
            }
        }

        /// <summary>
        /// Transform a XmlFo document in a pdf and save the pdf to a file
        /// </summary>
        /// <param name="xmldocFo">string containing the Fo document</param>
        /// <param name="strFilename">string representing the path to the output file</param>
        static protected void Transform( string xmldocFo, string strFilename )
        {
            // Run the full FO doc through the engine to create a pdf
            Engine e = new Engine();

            try
            {
                sbyte[] sPdf = e.Run( xmldocFo );

                int sz = sPdf.Length;
                byte[] pdf = new byte[sz];
                for(int i=0; i<sz; i++)
                    pdf[i] = (byte) sPdf[i];

                //Write output file
                FileStream fs = new FileStream( strFilename, FileMode.Create );
                BinaryWriter sw = new BinaryWriter( fs );
                sw.Write( pdf );
                sw.Close();
                fs.Close();
            } 
            catch(org.apache.fop.apps.FOPException fope) 
            {           
                Console.WriteLine( fope.getRootException().getMessage() );
            }
        }
    }
}

To be able to use this code it is necessary:

  1. Rename Fop.Net.dll that you downloaded in ApacheFop.Net.dll
  2. To add a reference to ApacheFop.dll
  3. To add a reference to vjslib.dll installed by "Microsoft Visual J # NET Redistributable Package"
  4. To add using ApacheFop;

It is noticed that all the transformation is made using two lines of code:

Engine e = new Engine();
sbyte[] sPdf = e.Run( xmldocFo );

Implementation

In order to create a small utility which will use for the transformation in both cases, to create a new project of the type "Console Application." To add the references like explaining a little higher. Then to modify your project to obtain:

using System;
using System.IO;
using System.Xml;
using System.Xml.Xsl;
using ApacheFop;


namespace Fop
{
    class Transformer
    {
        [STAThread]
        static void Main(string[] args)
        {
            if ( args.Length == 3 ) 
            {
                XmlDocument dataDoc = new XmlDocument();
                dataDoc.Load( args[0] );

                // Transformation du XML en FOP à l'aide de XSLT
                XslTransform xslt = new XslTransform();
                xslt.Load( args[1] );
                StringWriter fullFoDoc = new StringWriter();
                xslt.Transform(dataDoc.CreateNavigator(), null, fullFoDoc);

                //Transformation du FOP en PDF
                Transform( fullFoDoc.ToString(), args[2] );         
            }
            else if ( args.Length == 2 ) 
            {
                StreamReader sr = new StreamReader( args[0] );

                //Transformation du FOP en PDF
                Transform( sr.ReadToEnd(), args[1] );           
            }
            else
            {
                Console.WriteLine("Usage: fop.exe file.xml file.xsl file.pdf");
                Console.WriteLine("    or fop.exe file.fo file.pdf");
            }
        }

        /// <summary>
        /// Transform a XmlFo document in a pdf and save the pdf to a file
        /// </summary>
        /// <param name="xmldocFo">string containing the Fo document</param>
        /// <param name="strFilename">string representing the path to the output file</param>
        static protected void Transform( string xmldocFo, string strFilename )
        {
           // Run the full FO doc through the engine to create a pdf
            Engine e = new Engine();
            try
            {
                sbyte[] sPdf = e.Run( xmldocFo );

                int sz = sPdf.Length;
                byte[] pdf = new byte[sz];
                for(int i=0; i<sz; i++)
                    pdf[i] = (byte) sPdf[i];

                //Write output file
                FileStream fs = new FileStream( strFilename, FileMode.Create );
                BinaryWriter sw = new BinaryWriter( fs );
                sw.Write( pdf );
                sw.Close();
                fs.Close();
            } 
            catch(org.apache.fop.apps.FOPException fope) 
            {           
                Console.WriteLine( fope.getRootException().getMessage() );
            }
        }
    }
}

If the utility is called with three parameters, i.e. a file XML, a file XSL and the way of safeguard of file pdf, then files XML are charged in memory using a XmlDocument object and are transformed into FOP using file XSL and of a XslTransform object. Then the Transform method which transforms a file FOP into pdf is called using the result of the transformation and of the way of safeguard of the PDF.

In the case or the utility is called with two parameters, the program charges file FOP represented by the first parameter using a StreamReader object and calls the Transform method which will transform this file FOP into pdf.

Conclusion

The use of XML and NFop makes it possible to create a whole of document in different format. For my part I use this technique to write the articles which I publish on my Web site Tech Head. I write an article in a format XML and I have a template XSL to publish the article on Tech Head, another for the Codeproject site and the last to generate a file pdf for Tech Head. That enables me to write article only once and to publish it on different site without having to improve each returned. Although the bearing is not yet complete this version of NFop makes it possible to badly make not thing already and allows an enormous saving of time.