Welcome!

PowerBuilder Authors: Chris Pollach, Yeshim Deniz, Jayaram Krishnaswamy, Kevin Benedict, Avi Rosenthal

Related Topics: PowerBuilder

PowerBuilder: Article

Using FOP to Handle Formatting of Large Text Blocks in DataWindow Output

Using FOP to Handle Formatting of Large Text Blocks in DataWindow Output

It's been the bane of PowerBuilder development since day one. You have a DataWindow that contains one or more text blocks that, when previewed for printing or printed, span a page boundary. The result: the DataWindow incorrectly handles portions of the text. You may find some text on the first page that is repeated on the next page, or some text may be missing entirely, or the text may end up overwriting subsequent report objects. The bottom line is that the results are unusable, and it often takes a great deal of tweaking to get adequate results. The good news is that I found at least one method of addressing the issue. The bad news is that the path to get there was rather convoluted. This article describes both.

Beginning with PowerBuilder 9, the DataWindow has had the capability of exporting into XSLFO (XSL formatting objects) format. XSLFO is a variation of XML that contains formatting information in addition to the data. It is intended for use by a FOP (formatting objects processor) to render into any number of final output formats (e.g., PDF, RTF, HTML, etc.). In some sense it's similar to HTML, in that it contains formatting information and also because the syntax is somewhat similar. If you want to learn more about the actual structure and syntax of XSLFO documents, I recommend the tutorial on the w3schools site: www.w3schools.com/xslfo/default.asp. Referring to that may be helpful when I start discussing some of the current limitations of PowerBuilder's XSLFO implementation. There is another good tutorial at the RenderX site: www.renderx.com/tutorial.html. If you want to work directly with XSLFO documents and render them to PDF manually to see the result, I'd recommend the editX editor: www.editix.com/

The primary reason that PowerBuilder supports XSLFO is so that rendering to a PDF can be done through the XSLFOP! method rather than the Distiller! method. Sybase supplies the 0.20.4 version of Apache FOP with the product; you'll find it in the %SYBASEHOME%\Shared\PowerBuilder\fop-0.20.4 directory. Since PowerBuilder is already capable of generating a PDF through XSLFOP!, and XSLFO is capable of handling large text blocks easily, the original idea was to take the XSLFO output from the DataWindow and tweak it to ensure that the large text blocks were handled correctly before handing it over to the FOP for conversion to a PDF.

That original approach was based on the faulty assumption that, similar to HTML, the bounding area of the text block might have inappropriately calculated dimensions, but that the various areas within the document were independent of one another except they had a particular sequence. What actually turns out to be the case is that when PowerBuilder generates XSLFO, it generates absolute coordinates for everything in the document. That's actually good for making sure that the generated PDF is an exact representation of the original DataWindow. Unfortunately, that's exactly what we don't want.

As it turns out, there are a number of other areas in which PowerBuilder's XSLFO implementation is a bit anemic. They include:
•  If the DataWindow contains a Page n of nnn computed column, what gets exported is:

Page <fo:page-number/> of X

where X is a fixed value. We don't want that in our documents, because once we get the large text flowing correctly, the total number of pages is likely to change from what PowerBuilder originally calculated.

It is possible to create a similar compute in XSLFO. We just need to add a block element to the end of the document with an ID, and then in the page number reference just add a fo:page-number-citation that refers to that flow ID.

•  If there is a header and a footer on a DataWindow, the <fo:region-body> gets defined with a margin-bottom the same size as the <fo:region-after>. That's the way it should be. However, there's no matching margin-top to match the height of the <fo:region-before>. There's also no extent defined for the <fo:region-before>

•  If there is a header and footer on the DataWindow, the simple-page-master gets created with the following sections in the following order:

<fo:region-body>
<fo:region-after>
<fo:region-before>

The <fo:region-before> is supposed to be declared before the <fo:region-after> in a simple-page-master.

•  The DataWindow I was working with for testing included radio buttons for one of the columns. When those were rendered in the XSLFO, it was done with a followed by a . An instream-foreign-object isn't a valid child element of a block-container. There is supposed to be an fo:block between the block-container and the instream-foreign-object.

Perhaps one of the reasons that the PowerBuilder implementation looks the way it does is because they are targeting an older version of Apache FOP that only implements a rather limited subset of the 1.0 WC3 Recommendation for the format. The more recent version of Apache FOP (0.93) supports more of the 1.0 WC3 Recommendation as well as portions of the 1.1 Working Draft.

One critical limitation I found in the 0.20.4 version of Apache FOP is that it doesn't support non-absolute positioning, which is essential for our custom implementation to work. PowerBuilder doesn't calculate the boundaries for the large text blocks correctly, but that doesn't mean we want to be responsible for calculating it on our own. The reason we want to use XSLFO is to remove the need to do the positioning calculation altogether and just let the FOP handle it on its own. We're going to use the 0.93 version of Apache FOP for this implementation. More on that later.

Since the XSLFO that the DataWindow natively generates is lacking for our purposes, my next approach was to create an XML export template that simply generated XSLFO rather than just XML. If you've checked out the w3schools site or are already familiar with XSLFO, you'll know that the tags all begin with "fo:". One thing I discovered is that if you include such a tag prefix in a PowerBuilder XML export template, PowerBuilder won't export anything. It won't throw an error or return an error message, but it also won't export the data. You'll need to leave the "fo:" prefix off of the tags and then add them on once the export is complete.

However, for a number of reasons, primarily because I wanted something I could use more generically rather than having to custom design an XML export template for every DataWindow I needed to handle, I ended up creating a custom class to do the XSLFO export. If you had to generate XML or HTML from PowerBuilder before it was a native feature, you're probably familiar with the process. The main difference is the tags you use to surround the data. Some comparison to HTML might be in order (see Table 1). Obviously some of the formatting options will change; these are just what I used.

IBM has a much more detailed document describing the correlation between XSLFO and HML at www.ibm.com/developerworks/library/x-xslfo2app/.

At this point, we have a method of generating XSLFO in the format we want and we can use Apache FOP 0.93 to render it to PDF. You can obtain more information on Apache FOP at their Website: http://xmlgraphics.apache.org/fop/. In particular, the download mirrors are listed at www.apache.org/dyn/closer.cgi/xmlgraphics/fop from which you'll want to grab fop-0.93-bin-jdk1.4.zip.


More Stories By Bruce Armstrong

Bruce Armstrong is a development lead with Integrated Data Services (www.get-integrated.com). A charter member of TeamSybase, he has been using PowerBuilder since version 1.0.B. He was a contributing author to SYS-CON's PowerBuilder 4.0 Secrets of the Masters and the editor of SAMs' PowerBuilder 9: Advanced Client/Server Development.

Comments (0)

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.