Solved

Creating a pdf via XSLT inside a web application hosted on a j2ee container

Posted on 2013-11-08
9
16 Views
Last Modified: 2016-07-11
This is the setup:

A web application, hosted on jboss - could be any other container. From the web app, using a browser, users query the backend for various reports. The reports are displayed on the screen. The vendor has provided options to save the report results into csv, xml and html. This is done by use of xsl transformations.

When the user clicks on, say, Save to csv, a js script is called that sends the report data on the screen to the xsl and once the transformation is done, the user is prompted to save the generated file (or open it in the whatever app is associated with the file type)

Note that all the above is done on the fly. Some of the code behind are closed but the xsls are available for modification.

Now, I am required to extend the web app to generate a pdf based on a custom template using the query data being passed via js.

I was thinking I can use the html transformation as a basis for converting to pdf. The xsl for html transformation looks like this:

<?xml version="1.0"?>
<xsl:template match="/">
    <html>
        <body topmargin="2" leftmargin="2">
            <title>
                <xsl:value-of select="/responseDetails/window/panes/pane/dataSection/enqResponse/title" />
            </title>

            <TABLE cellSpacing="0" cellPadding="0">
                <table>
                    <xsl:choose>
                        <!-- Process each report page data -->
                        <xsl:when test="/responseDetails/window/panes/pane/dataSection/enqResponse/pageData !=''">
                            <xsl:for-each select="/responseDetails/window/panes/pane/dataSection/enqResponse/pageData">
                                <xsl:call-template name="Header"/> 
                                <xsl:call-template name="ColumnHeaders"/>
                                <xsl:call-template name="Datam"/>
                                <xsl:call-template name="Footer"/>
                            </xsl:for-each> 
                        </xsl:when>
                        <!-- Process report data -->
                        <xsl:otherwise>
                            <xsl:call-template name="Header"/> 
                            <xsl:call-template name="ColumnHeaders"/>
                            <xsl:call-template name="Datam"/>
                            <xsl:call-template name="Footer"/>
                        </xsl:otherwise>
                    </xsl:choose>
                </table>
            </TABLE>
        </body>
    </html>
</xsl:template>

<!-- Template for Header which decides to extract header data page by page or whole -->
<xsl:template name="Header">
    <xsl:choose>
        <xsl:when test="/responseDetails/window/panes/pane/dataSection/enqResponse/pageData!=''">
            <tr>
                <xsl:for-each select="./header/r">
                    <xsl:call-template name="Headers"/>
                </xsl:for-each>
            </tr>
        </xsl:when>
        <xsl:otherwise>
            <tr>
                <xsl:for-each select="/responseDetails/window/panes/pane/dataSection/enqResponse/header/r">
                    <xsl:call-template name="Headers"/>
                </xsl:for-each>
            </tr>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

<!-- Template for datam which decides to extract data page by page or whole -->
<xsl:template name="Datam">
    <xsl:choose>
        <xsl:when test="/responseDetails/window/panes/pane/dataSection/enqResponse/pageData!=''">
            <xsl:for-each select="./r">
                <xsl:call-template name="Data"/>
            </xsl:for-each>
        </xsl:when>
        <xsl:otherwise>
            <xsl:for-each select="/responseDetails/window/panes/pane/dataSection/enqResponse/r">
                <xsl:call-template name="Data"/>
            </xsl:for-each>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

<!-- Template for footer which decides to extract footer data page by page or whole -->
<xsl:template name="Footer">
    <xsl:choose>
        <xsl:when test="/responseDetails/window/panes/pane/dataSection/enqResponse/pageData!=''">
            <xsl:for-each select="./footer">
                <xsl:call-template name="Footers"/>
            </xsl:for-each>
            <xsl:text> </xsl:text>
            <xsl:text>&#xa;</xsl:text>
        </xsl:when>
        <xsl:otherwise>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

<!-- Template for headers -->
<xsl:template name="Headers">
                <tr>
                    <xsl:for-each select="c">
                        <xsl:choose>
                            <xsl:when test="cap != '' ">
                                <td>
                                    <b>
                                        <font color="#FF8400">
                                            <xsl:value-of select="cap"/>
                                        </font>
                                    </b>
                                </td>
                            </xsl:when>
                            <xsl:otherwise>
                                <xsl:choose>
                                    <xsl:when test="class!=''">
                                        <td>
                                            <b>
                                                <font color="#FF8400">
                                                    <xsl:value-of select="cap" />
                                                </font>
                                            </b>
                                        </td>
                                    </xsl:when>
                                    <xsl:otherwise>
                                        <td>
                                            <b>
                                                <font color="#FF8400">
                                                    <xsl:value-of select="." />
                                                </font>
                                            </b>
                                        </td>
                                    </xsl:otherwise>
                                </xsl:choose>   
                            </xsl:otherwise>
                        </xsl:choose>
                    </xsl:for-each>
                </tr>
</xsl:template>

<!-- Template for column headers -->
<xsl:template name="ColumnHeaders">
    <tr>
        <xsl:for-each select="/responseDetails/window/panes/pane/dataSection/enqResponse/cols">
            <xsl:for-each select="c">
                <td>
                    <b>
                        <font color="#FF8400">
                            <xsl:value-of select="." />
                        </font>
                    </b>
                </td>
            </xsl:for-each>
        </xsl:for-each>
    </tr>
</xsl:template>

<!-- Template for data -->
<xsl:template name="Data">
    <xsl:choose>
            <xsl:when test="position() mod 2 = 0">
                <td>
                    <tr>
                        <xsl:for-each select="c">
                            <td bgColor="white">
                                <xsl:value-of select="cap" />
                            </td>
                        </xsl:for-each>
                    </tr>
                </td>
            </xsl:when>
            <xsl:otherwise>
                <td>
                    <tr>
                        <xsl:for-each select="c">
                            <td bgColor="#eeeeee">
                                <xsl:value-of select="cap" />
                            </td>
                        </xsl:for-each>
                    </tr>
                </td>
            </xsl:otherwise>
        </xsl:choose>
</xsl:template>

<!-- Template for footers -->
<xsl:template name="Footers">
    <tr>
        <xsl:for-each select="r">
                <tr>
                    <xsl:for-each select="c">
                        <xsl:choose>
                            <xsl:when test="cap != '' ">
                                <td>
                                    <b>
                                        <font color="#FF8400">
                                            <xsl:value-of select="cap"/>
                                        </font>
                                    </b>
                                </td>
                            </xsl:when>
                            <xsl:otherwise>
                                <td>
                                    <b>
                                        <font color="#FF8400">
                                            <xsl:value-of select="." />
                                        </font>
                                    </b>
                                </td>
                            </xsl:otherwise>
                        </xsl:choose>
                    </xsl:for-each>
                </tr>
            </xsl:for-each>
    </tr>
</xsl:template>

Open in new window


No physical files are involved in this.

My question is, how can I extend the xsl above to print the resulting html into pdf? At this point, I have to admit I dont even know how to access the resulting data from code since I am a total newbie in xslt AND I dont know how to debug xsl at runtime.

If this is possible, then I figure I could pass the resulting data to iText or Apache FOP processor

Either way, there should be NO physical files created on the server side. The output should be sent to user for opening or saving.

I have come across many other tools and converters like XDocReport, JODConverter, docx4j, etc.

If only I can figure out how to put it all together within the existing framework!

There is still the issue of using the custom templates (Probably created using word) but that will be phase 2. I just want to print to pdf first
0
Comment
Question by:masterl
  • 5
  • 2
9 Comments
 
LVL 60

Expert Comment

by:Geert Bormans
Comment Utility
I would assume that if you have XSLT to generate HTML, you could use a similar XSLT to generate XSL:FO. After that you need to hook in FOP of course, but if the process stores its results on a disk somewhere in either CSV or anything else, PDF should not be too hard
0
 
LVL 60

Expert Comment

by:Geert Bormans
Comment Utility
http://www.w3schools.com/xslfo/default.asp
gives you an idea on how to set up a page using XSL:FO
0
 

Author Comment

by:masterl
Comment Utility
As stated in the question, there are no physical files created on the server. The transformed output is sent back to the browser for the user to save. I want a similar for pdf
0
Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 
LVL 60

Accepted Solution

by:
Geert Bormans earned 500 total points
Comment Utility
ah sorry, misread that

actualy does not matter, if it is a j2ee container, you can access the tree generated from the XSLT and push that to FOP. Java code snippets examples for that are on the apache graphics web site. You could have the XSLT handled by FOP too (in the code snippets you will find it clear which transformer to rule out or use)
Just make sure you pass the right mimetype back to the browser, so the browser knows it is PDF and will save it accordingly

this could help you
http://xmlgraphics.apache.org/fop/0.95/embedding.html
0
 

Author Comment

by:masterl
Comment Utility
First of all, let me say am really impressed with ee. I have posted this question in many other forums with ZERO response for many days. I post here and within 1 hr I can see some light at the end of the tunnel. Thanks a lot guys.

@Gertone,
you can access the tree generated from the XSLT
Looking at the xsl I posted, how can I get the result of the transformation? Does it like save in a variable?

The mimetype is already taken care of by the js that calls this xsl and the code that posts the response back to the browser.

Thank you again. Let me see what I can cook up from the link you posted
0
 
LVL 60

Assisted Solution

by:Geert Bormans
Geert Bormans earned 500 total points
Comment Utility
There is two things

- the XSLT just generates XSL-FO (that is a language that describes formatting objects). That process is similar to the one that creates csv or xml reports (provided XSLT is used for those)

- then there is an extra step involved, turning teh Formatting Objects into PDF. For that you need an extra processor, FOP

There is java code in your container that executes the XSLT for CSV or XML or HTML, you need that code to execute a similar but different XSLT that creates the XSL-FO. But then, you need to expand the Java code you have, to execute the FO processor (most likely FOP) right after the XSLT transformation. I don't know whether that would be from a variable, or a piped call, that is up to you. There is definitely no XSLT variable involved. The FOP processing happens outside the XSLT (after it actually) The XSLT does not care what you do with its result
0
 
LVL 60

Expert Comment

by:Geert Bormans
Comment Utility
accept https://#a39633274
assist https://#a39633379

The required process is explained in detail and generically applicable, meaning it is relevant to others
0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

A short article about problems I had with the new location API and permissions in Marshmallow
Whether you’re a college noob or a soon-to-be pro, these tips are sure to help you in your journey to becoming a programming ninja and stand out from the crowd.
This tutorial explains how to use the VisualVM tool for the Java platform application. This video goes into detail on the Threads, Sampler, and Profiler tabs.
In this fourth video of the Xpdf series, we discuss and demonstrate the PDFinfo utility, which retrieves the contents of a PDF's Info Dictionary, as well as some other information, including the page count. We show how to isolate the page count in a…

772 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

14 Experts available now in Live!

Get 1:1 Help Now