LISTING 1

FOPExampleTables.sql

CREATE TABLE [dbo].[customers] (
	[customerid] [int] IDENTITY (1, 1) NOT NULL ,
	[customerfirstname] [varchar] (50) NOT NULL ,
	[customerlastname] [varchar] (50) NOT NULL ,
	[customercity] [varchar] (50) NOT NULL ,
	[customerstatecode] [varchar] (2) NOT NULL 
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[usstates] (
	[usstateid] [int] IDENTITY (1, 1) NOT NULL ,
	[usstatecode] [varchar] (2) NOT NULL ,
	[usstatename] [varchar] (25) NOT NULL 
) ON [PRIMARY]
GO

LISTING 2

basicForm.cfm

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head><title>Basic Form</title></head>
<body>
   <cfquery name="getstates" datasource="FOPExample">
	select usstatecode, usstatename, usstateid
	from usstates
	order by usstatename
   </cfquery>
   <form action="generatexml.cfm" method="post">
   Select 1 or more states:<br>
   <select name="usstates" multiple>
	<cfoutput query="getstates">
	   <option value="#getstates.usstateid#">#getstates.usstatename#
	</cfoutput>
   </select>
   <input type="submit" value="submit">
   </form>
</body>
</html>


LISTING 3

generateXML.cfm

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head><title>Generate the XML</title></head>
<body>

<cfquery name="getcustomers" datasource="FOPExample">
	select c.customerfirstname, c.customerlastname, c.customercity,
	c.customerstatecode, u.usstatename
	from customers as c
	inner join usstates as u
		on c.customerstatecode = u.usstatecode
	where u.usstateid IN (#FORM.usstates#)
	order by u.usstatename, c.customercity, c.customerlastname
</cfquery>

<!--- Create an XML string named MyXML --->
<cfxml variable="MyXml">
  <project name="FOPExample">
    <cfoutput query="getcustomers" group="usstatename">
      <usstate name="#getcustomers.usstatename#">
        <customers>
          <cfoutput>
<person city="#getcustomers.customercity#"
statecode="#getcustomers.customerstatecode#">#getcustomers.customerfirstname#
#getcustomers.customerlastname#</person>
          </cfoutput>
        </customers>
      </usstate>
    </cfoutput>
  </project>
</cfxml>

<cffile action="WRITE" file="#ExpandPath('Output.xml')#" output="#ToString(MyXML)#">
<p> The XML has been generated.</p>
<a href="TransformXML.cfm" target="_blank">View Generated PDF</a>

</body>
</html>

LISTING 4

Output.xml

<?xml version="1.0" encoding="UTF-8"?>
<project name="FOPExample">
   <usstate name="California">
     <customers>
         <person city="Sacremento" statecode="CA">Mary Wilson</person>
         <person city="San Diego" statecode="CA">Matt Collins</person>
     </customers>
   </usstate>
   <usstate name="Colorado">
     <customers>
         <person city="Aurora" statecode="CO">Joe Williams</person>
         <person city="Colorado Springs" statecode="CO">Jackie
		 Robinson</person>
         <person city="Denver" statecode="CO">Amanda Benson</person>
         <person city="Denver" statecode="CO">Jeff Goings</person>
         <person city="Denver" statecode="CO">Nate Nelson</person>
     </customers>
   </usstate>
   <usstate name="Minnesota">
     <customers>
     <person city="Minneapolis" statecode="MN">Michael Bennett</person>
         <person city="Minneapolis" statecode="MN">Daunte Culpepper</person>
         <person city="Minneapolis" statecode="MN">Randy Moss</person>
     </customers>
   </usstate>
</project>

LISTING 5

fopExample.xsl

<?xml version="1.0" encoding="utf-8"?>

<xsl:stylesheet
   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
   xmlns:fo="http://www.w3.org/1999/XSL/Format"
   version="1.0">
		
   <xsl:template match="/project">
      <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
	     <!-- defines page layout -->
		 <fo:layout-master-set>
		    <!-- layout for the first page -->
			<fo:simple-page-master 
			   master-name="only"
			   page-height="29.7cm" 
			   page-width="21cm"
			   margin-top="1cm" 
			   margin-bottom="2cm" 
			   margin-left="2.5cm" 
			   margin-right="2.5cm">
			   <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>
		 <!-- end: defines page layout -->
		
<!-- actual layout -->
<fo:page-sequence master-reference="only" initial-page-number="1">
		
			<!-- header -->
			<fo:static-content flow-name="xsl-region-before">
   			   <fo:block 
			      text-align="end" 
				  font-size="10pt" 
				  font-family="serif" 
				  line-height="14pt" >
			         Customer List - p. <fo:page-number/>
			   </fo:block>
			</fo:static-content> 
		
	<fo:flow flow-name="xsl-region-body">
		<!-- defines text title level 1-->
			 <fo:block 
			      font-size="24pt" 
				  font-family="sans-serif" 
				  line-height="30pt"
				  space-after.optimum="15pt"
				  background-color="grey"
				  color="white"
				  font-weight="bold"
				  padding-left="5px"
				  padding-top="2px">
					 <!-- output level 1 name -->
				     <xsl:value-of select="@name"/>
			   </fo:block>
		
	<xsl:for-each select="usstate">
	<!-- defines text title level 2-->
		 <fo:block 
			font-size="18pt" 
			font-family="sans-serif" 
			line-height="20pt"
			space-before.optimum="10pt"
			space-after.optimum="10pt"
			text-align="start"
			padding-top="0pt">
<!-- output level 2 name -->
<xsl:value-of select="@name"/>
		</fo:block>
						
<xsl:for-each select="customers/person">
<!-- defines the final text level -->
			<fo:block 
			font-size="12pt" 
			font-family="sans-serif" 
	line-height="15pt"
	space-after.optimum="3pt"
	text-align="start">

<!-- output the contents wrapped in final level -->		
	<xsl:value-of select="."/>
 	<!-- inline formatting -->
  <fo:inline font-style="italic" font-size="10pt">
	of <xsl:value-of select="@city"/>, <xsl:value-of select="@statecode"/>
		         </fo:inline>
		       </fo:block>
		      </xsl:for-each>
		    </xsl:for-each>
		  </fo:flow>
	      </fo:page-sequence>
	   </fo:root>
   </xsl:template>   
</xsl:stylesheet>

LISTING 6

transformXML.cfm

<!--- turn off debugging to prevent errors when displaying pdf content --->
<cfsetting showdebugoutput="No"> 

<!--- set filenames --->
<CFSET MyStylesheet = "FOPExample.xsl">
<cfset pdfFile = "Result.pdf">
<cfset MyXml = "Output.xml">

<!--- get contents of xml file and xsl file --->
<CFFILE ACTION="READ" FILE="#ExpandPath(MyXml)#" VARIABLE="XMLFileContent">
<CFFILE ACTION="READ" FILE="#ExpandPath(MyStylesheet)#" VARIABLE="XSLFileContent">

<!--- perform xml transformation with XMLFileContent agaisnt XSLFileContent --->
<CFSET TransformedXmlCode = XmlTransform(XMLFileContent, XSLFileContent)>

<!--- now invoke the FOP component - pass in transformed xml and pdf file to be created --->
<cfinvoke component="FOP" method="ConvertStringToPDF"
foString="#TransformedXMLCode#" pdfFile="#ExpandPath(pdfFile)#">

<!--- No display PDF file to browser --->
<cfcontent file="#ExpandPath(pdfFile)#" deletefile="yes" type="application/pdf">

LISTING 7

fop,cfc

<cfcomponent>
  <!--- Initialize the FOP driver from xml.apache.org --->
  <cfset THIS.driver = CreateObject("java", "org.apache.fop.apps.Driver")>
  <cfset THIS.lockname = CreateUUID()>

  <cffunction name="ConvertFileToPDF" access="public">
    <cfargument name="foFile" type="string" required="true">	
    <cfargument name="pdfFile" type="string" required="true">	
		
    <!--- Set up Java input source --->		
		<cfset var input = CreateObject("java", "org.xml.sax.InputSource")>
		<cfset input.init( ARGUMENTS.foFile)>

    <!--- Proceed with PDF generation --->
    <cfset private_generatePDF(input, pdfFile)>
  </cffunction>
	
  <cffunction name="ConvertStringToPDF" access="public">
    <cfargument name="foString" type="string" required="true">	
    <cfargument name="pdfFile" type="string" required="true">	
	<!-- set arguments values -->

  <!--- Set up Java input source --->	
	<cfset var reader = CreateObject("java", "java.io.StringReader")>	
	<cfset var input = CreateObject("java", "org.xml.sax.InputSource")>
		<cfset reader.init(foString)>
		<cfset input.init(reader)>

   <!--- Proceed with PDF generation --->
   <cfset private_generatePDF(input, pdfFile)>
  </cffunction>
	
	<cffunction name="private_generatePDF" access="private">
	  <cfargument name="input" type="any" required="true">
	  <cfargument name="pdfFile" type="string" required="true">

  <!--- Output stream for writing PDF file --->	
	<cfset var output = CreateObject("java", "java.io.FileOutputStream")>

	<!--- Get ready to do the PDF generation --->
  <cflock name="#THIS.lockname#" type="exclusive" timeout="10">
	<cflock name="#ARGUMENTS.pdfFile#" type="exclusive" timeout="10">
   <!--- Turn on the output stream --->  
	  	<cfset output.init( ARGUMENTS.pdfFile )>
	<!--- Hook the FOP driver to the input/output --->		
		<cfset THIS.driver.setInputSource(input)>
		<cfset THIS.driver.setOutputStream(output)>
		<!--- Perform the actual PDF generation --->
			<cfset THIS.driver.run()>	
	      <!--- Turn off the output stream --->
	  	<cfset output.close()>
		</cflock>
  	</cflock>
	</cffunction>
</cfcomponent>