| By Nate Nelson | Article Rating: |
|
| July 14, 2004 12:00 AM EDT | Reads: |
17,128 |
Here's how to put your knowledge of HTML to work by creating free PDFs with FOP (Formatting Objects Processor).
In the May issue of CFDJ, I covered the basics of utilizing FOP from Apache to dynamically create free PDFs in your ColdFusion application. If you enjoyed that article you will certainly enjoy this one as we dive deeper into the capabilities of this process. After reading both articles you should be able to not only generate free PDFs but also to display presentable results simply by using the HTML that you already know. In this article I will demonstrate how to do this by further defining XSLT and XSL-FO.
A Quick Recap
In part 1 of this article, available at www.sys-con.com/story/?storyid=44771&DE=1 , I covered everything you need to know in order to create your first free dynamic PDF using CF, including an introduction to FOP, how to generate and transform XML, and how to invoke FOP.
What's Next?
If you read part 1 of this article, you may be thinking something like "Okay, this is pretty easy.... I can create a PDF in my ColdFusion app with no sweat, but now I want to make it look nice and add some formatting to it." After all, if we were just spitting out text all the time it wouldn't even be necessary to use a PDF file to display your results. In this article I'm going to go back to further define a couple of topics that I briefly touched on last month (generating the XML and creating the XSL file). This time while generating the XML we will add in some of your favorite HTML tags to include images, tables, lists, and some miscellaneous text decoration commands. I will also briefly revisit invoking FOP and displaying the PDF to include a more efficient way of handling these tasks based on reader feedback from last month. I bet you're wondering how FOP knows how to automatically render these HTML tags and why I didn't tell you this before.
This is accomplished by doing a lot of front work in the XSL file using XSLT and XSL-FO. Working with XSL-FO can be complex; in fact, it is one of the largest spec documents at the World Wide Web Consortium, totaling over 400 pages. Don't worry though, you don't have to master XSLT or XSL-FO in order to use this process, nor do you even need to be good with them. One of the beauties of this process is that the XSL is completely separate from your CF application, allowing you to use other resources to create the XSL file. I will try to make this as simple as possible for you by not only demonstrating how to create your own XSL, but also by providing a complete XSL file that will transform the HTML tags that I will discuss in this article.
Sound interesting? Let's get started!
The Example
In this article I will use the results of a simple query on one of the sample databases that come with the ColdFusion install. The following code snippet contains the query I will be using:
<cfquery name="getemployees" datasource="exampleapps">
select top 10 firstname,lastname,phone,startdate,title
from tblEmployees
where title in ('engineer','web guru')
order by title,lastname,firstname
</cfquery>
The result data will be used to demonstrate tables, unordered lists, and ordered lists. I will use a simple paragraph to demonstrate the other HTML tags.
Preparing for FOP
To create a PDF using FOP requires the input of well-formed XML transformed with XSL-FO. We will generate the XML with ColdFusion by using simple XHTML code wrapped in the <CFXML> tag. To transform the XML we will use the XMLTransform function in ColdFusion and transform it with the contents of a prepared XSL file. The XSL file contains all of the necessary components to format the tags used in the generated XML. Next, we will create the XSL file by integrating XSL-FO and XSLT.
Integrating XSLT and XSL-FO
Let's go back to the basic format of the XSL-FO file that we worked with in part 1. I explained the pieces of the XSL file that FOP expects; be sure to continue to use them. If you are not familiar with this, review part 1 or refer to the complete source code for this article at www.sys-con.com/coldfusion/sourcec. cfm. Last month we used the for-each XSL element to loop over a simple piece of XML code and then used fo:blocks in our loops to format the group of code. That worked well but was very simple and limited. Let's go a little deeper into this part of the process and get a glimpse of what you can become truly of capable of by using FOP to create your PDFs.
Integrating XSLT and XSL-FO allows us to dynamically create all of the XSL-FO needed to create our PDF. We did some of this last time, but in a very limited fashion. Now we will maximize the use of templates to help us do this. Templates are the individual statements that we will use to create the formatting transformation for the simple HTML tags so that FOP can render them.
The following code snippet contains the template I use for the HTML bold tag <strong>. As you can see, the template is wrapped in <xsl:template>. The match attribute of <xsl: template> is used for selecting nodes in an XML string through the use of patterns. A pattern is the syntax we will use to navigate around the XML source tree. Pattern syntax is similar to the command-line syntax used in most operating systems to navigate through directories. As you can see, we are looking for any node matches to the word strong, which will allow us to format anything contained in that node. The code inside the template wrapper can change depending on what you want to do. For bold we use an inline fo style. This could also be any <fo:block> or other XSL-FO element, such as <fo:table>. Then we add the <xsl:apply-templates/> element, which triggers the processing of the children of the node in our XML source that matches the template. These children don't include only other nodes. Elements, attributes, text, and comments are also processed by using the apply-templates element.
<xsl:template match="strong"> <fo:inline font-weight="bold"><xsl:apply-templates/></fo:inline> </xsl:template>
Now let's move on to the formatting of the individual HTML tags.
Images, Paragraphs, and Miscellaneous Style Tags
The first tag we will tackle is the image tag; it is much like your everyday <img> tag. You give it a source location of the image and you can specify a height and a width for the image. The current version of FOP requires either an absolute file path or a full URL path. Here, I simply use the ColdFusion function expandPath() to return the absolute file path to the image. The XSL template for img that I have provided looks a little complex, but it's actually a somewhat common code snippet I have seen used to render images. It contains the code needed to handle the image attributes correctly. Here is an example of what a finished XSL-FO image tag might look like.
<fo:external-graphic src="#expandPath(logo.jpg)#" height="50px" width="150px"/>
Next is the header (H1), which I will show in detail because I have used an attributes group with it instead of naming the attributes right in the <fo:block>. This method can be useful if there is a common set of attributes that you apply in a few different places, or it can be nice to just define the attributes at the top of the file so that you don't have to go searching for them. Following is the attributes set I have used for the <h1> tag.
<xsl:attribute-set name="h1"> <xsl:attribute name="font-size">24pt</xsl:attribute> <xsl:attribute name="font-weight">bold</xsl:attribute> <xsl:attribute name="space-after">10pt</xsl:attribute> </xsl:attribute-set>
With various attribute sets such as this in place, they can be accessed quickly and easily, as shown in the following snippet.
<xsl:template match="h1"> <fo:block xsl:use-attribute-sets="h1"> <xsl:apply-templates/></fo:block> </xsl:template>
Another very useful tag – but one that's a little different from the first two I've shown – is the paragraph tag. In the paragraph template I have added the use of the align attribute. You will notice the xsl:if statement; this allows you to check for an optional attribute and, if it exists, to apply the value by using @nameOfAttribute.
<xsl:template match="p">
<fo:block text-indent="1em" space-before="2pt" space-after="12pt">
<!-- align attribute -->
<xsl:if test="@align">
<xsl:attribute name="text-align"><xsl:value-of
select="@align"/></xsl:attribute>
</xsl:if>
<xsl:apply-templates/>
</fo:block>
</xsl:template>
The next tag is the HTML anchor tag. When you see it in the provided code it looks complex; this is because it handles multiple attributes, much like the image tag. It is also a commonly used XSL template for the anchor tag. The difference here is that the anchor tag is used for more than one purpose; the provided code allows it to be used as a local anchor, local destination, and external destination link. The other tags included in the provided code are underline, italic, strike-through, and break. See Figure 1 for the display results of this first section. For the supporting XSL-FO code for images and anchor tags, refer to the section commented as "HTML Image and Anchor" in Listing 1. If you would like to see all of the XSL-FO code, as well as the basic XHTML code used to make the XML string, please refer to www.sys-con.com/coldfusion/sourcec.cfm.
Tables
Tables, as you can imagine, can be complicated. There are a lot of pieces to them, but luckily the tags are very similar to the HTML tags that you are probably used to. The easiest way to see the basic pieces is to look at Figure 2, where they are shown in comparison to their corresponding HTML tags. There are more pieces to the table formatting object, but these are the most commonly used ones.
The code to make the basic table is very similar to the HTML code you may have used to do something similar:
<table> <tr><th colspan="3" align="center" valign="center">header</th></tr> <tr><td>cell 1</td><td>cell 2</td><td>cell 3</td></tr> </table>
The actual XSL-FO table object has a table-body child, which has table-row children, which in turn have table-cell children. One addition to the XSL-FO code to note is the required use of the table-column element. FOP does not automatically figure out how many columns your table has, so a table-column element must be used for each column in your table. By using the XSL for each element and using patterns I was able to figure this out in the table template. You can see the complete code in the tables section of the XSL file in Listing 1. I have created the provided XSL to support colspan, rowspan, align, and valign on both the <th> and <td> tags. The <table> tag will support a width attribute. The tables used in this article are only basic examples. There are many other things that you can do with tables. For example, you can set up table-headers and table-footers that will repeat on breaking pages. To see all of the supporting XSL-FO code for creating tables, refer to the section in Listing 1 commented as "HTML Tables Begin Here". See Figure 3 for the results of the provided code. To find out more about tables you can refer to chapter 18 of the XML Bible, Second Edition, viewable at www.ibiblio.org/xml/books/bible2/chapters/ch18.html.
Lists
Now that you are more familiar with XSL formatting objects, it's a good time to dip into the details of formatting lists. I will cover unordered and ordered lists in this example. There are four XSL-FO elements used to create a list. An <fo:list-block> has <fo:list-item> children, which have <fo:list-item-label> and <fo:list-item-body> children. Lists can become very complex because of all the different spacing commands available. See Figure 4 to help you understand the different spacing commands and what they do. The following list corresponds to the letters marked in Figure 4:
A. Provisional-distance-between-starts
B. Provisional-label-separation
C. Start-indent for list-item-label
D. Start-indent for list-item-body
E. End-indent for list-item-label
F. End-indent for list-item-body
Unordered lists and ordered lists are very similar. For unordered lists you specify the specific bullet character, which is commonly done using the Unicode character entity, as you can see in the following code snippet.
<fo:list-item-label end-indent="label-end()" start-indent="1em"> <fo:block>•</fo:block> </fo:list-item-label>
Ordered lists are done the same way, except that instead of using the bullet character in the <fo:block> to generate the item numbers, you use the <xsl:number> element. To generate numbers you could use <xsl:number format="1. "/>. If you want to have more flexibility with your list items you can use the <xsl:choose> element (just like cfswitch), which allows you to specify a type on your HTML <li> tag. The provided XSL file is set up so that the HTML list commands you already know can be used in the XML to create lists. For the ordered lists I added the logic I mentioned earlier to allow the use of a type attribute on the <li> tag. With the provided XSL file the following type values are available: i, I, a, A, 1. See Figures 5 and 6 to view the output of the provided code. To see the actual XSL-FO code for these results, see the section in Listing 1 commented as "HTML Lists Begin Here". If you want to get into more detail with lists, I again recommend chapter 18 of the XML Bible at www.ibiblio.org/xml/books/bible2/chapters/ch18.html.
Invoking and Displaying the PDF
Now all we need to do is invoke the provided component, fop.cfc. Fop.cfc will call the necessary Java objects included with FOP to create the PDF. Last time we used <cfcontent> to display the PDF file in the browser. After last month's article was published I received a suggestion on another way to do this that I think is very cool and useful. Neil Giarratana sent me an e-mail with instructions on how to stream the PDF into the browser without ever creating a PDF file. However, there are pros and cons to this method. The main drawback is that it is not an officially supported technique. If you use this method, make sure to encapsulate it well so that it will be easy to change if the method is not functional in future versions of ColdFusion. The major pro of this method is that there is no need to access the directory on the server to save the PDF file. I have included the necessary code for this method in this article, but if you do not want to use it and would prefer to use a supported method, refer to the source code for part 1 at www.sys-con.com/story/?storyid=44771&DE=1 .
Neil's alternative method involves changing the called method of the java.io package in fop.cfc. In the previous version of fop.cfc we used the FileOutputStream method, but now we will use the ByteArrayOutputStream method. I have included the modified version of fop.cfc in Listing 2. When invoking fop.cfc there is no longer a need to use the PDFFile argument since it is not actually creating the PDF file. Instead, a ReturnVariable argument is added. In place of the <cfcontent> tag we used last time, we will now use a little block of cfscript that Neil sent me (see Listing 3). There is nothing wrong with the way we did this last time; as I mentioned, both methods have their pros and cons. This is just another great way to create a PDF.
Note: The complete source code for this article is too long to print, but is available at www.sys-con.com/coldfusion/sourcec.cfm.
Conclusion
Now you not only know how to create a free PDF, you can also make your results very presentable simply by using the HTML tags that you already know. Hopefully, you can now see the possibilities of this process and how useful it can be. There is still so much more that can be done with this process. If you read up on some resources for XSL-FO, you will see what I mean. There is no way I could completely cover everything in just a few articles. I hope to encourage more people to get started using this process. Hopefully, others will chime in with how they have used it. If you have any suggestions or comments on it, send them my way at natenelson@comcast.net. In future articles in this series I may eventually touch on encryption, tables of contents, indexes, coversheets, or SVG support. Feel free to send suggestions or comments on what you would most like to see. I look forward to hearing from you, but most important, have fun!
Resources
Published July 14, 2004 Reads 17,128
Copyright © 2004 SYS-CON Media, Inc. — All Rights Reserved.
Syndicated stories and blog feeds, all rights reserved by the author.
More Stories By Nate Nelson
Nate Nelson is a senior software developer for I*LEVEL, Inc., a software startup in Englewood, Colorado, where he leads development efforts of a commercial software product. He is a member of the Denver CFUG administration.
![]() |
Sahr Mbayo 09/16/04 02:33:01 PM EDT | |||
A page is already being presented with the help of style sheets. How would you incoporate this CSS file in creating the XML file? |
||||
![]() |
Tara Michelle 08/31/04 02:45:15 PM EDT | |||
Now how do I create a PDF from a file such as a word document? Can this be done with FOP too? |
||||
- Cloud Expo New York Call for Papers to Expire January 15, 2010
- My Three iPhone Predictions For 2010
- Adobe Fiddles with its Web Apps
- Adaptivity “Platinum Plus Sponsor” of Cloud Expo
- UPDATE: Adobe & IE Implicated as China’s Spy Holes
- Adobe Discusses Cloud Computing
- Microsoft WebsiteSpark: Get New Business Leads to Grow Your Business
- Adobe Flash on the Road to Nowhere
- Streaming Media in the Cloud by Amazon and Adobe
- Apple and Emotional Discussions Around Adobe Flash Player
- Jobs Has a Few Words for Google & Adobe & They Ain’t Pretty: Reports
- Built4Flash Launched by Farata Systems
- Cloud Expo New York Call for Papers to Expire January 15, 2010
- My Three iPhone Predictions For 2010
- Adobe Fiddles with its Web Apps
- Adobe Flex Developer Earns $100K in New York City
- Adaptivity “Platinum Plus Sponsor” of Cloud Expo
- Adobe Betas Target RIAs and Cloud Computing
- UPDATE: Adobe & IE Implicated as China’s Spy Holes
- Adobe Discusses Cloud Computing
- Microsoft WebsiteSpark: Get New Business Leads to Grow Your Business
- Adobe Flash on the Road to Nowhere
- Adobe Discusses Cloud Computing and Government
- Streaming Media in the Cloud by Amazon and Adobe
- The Next Programming Models, RIAs and Composite Applications
- Where Are RIA Technologies Headed in 2008?
- Constructing an Application with Flash Forms from the Ground Up
- AJAX World RIA Conference & Expo Kicks Off in New York City
- CFEclipse: The Developer's IDE, Eclipse For ColdFusion
- Personal Branding Checklist
- Adobe Flex 2: Advanced DataGrid
- Has the Technology Bounceback Begun?
- Building a Zip Code Proximity Search with ColdFusion
- i-Technology Viewpoint: We Need Not More Frameworks, But Better Programmers
- The Asynchronous CFML Gateway
- Web Services Using ColdFusion and Apache CXF
























