How to Dynamically Generate Static HTML Files Using Coldfusion
Introduction

As I have been learning more about Coldfusion I have constantly challenged myself by figuring out how to do make it do more complex things. One of the things I love about Coldfusion is that it is such a great high-level scripting language. Things that I can do in Coldfusion in a matter of minutes would take hours of programming in other languages based on the syntactical complexity of those languages alone. Coldfusion makes seemingly laborious tasks trivial, which is why I feel in many situations especially small to medium size web shops and projects it is the best path to take. It is economically efficient from a development perspective especially if you have it well mastered.

One of the challenges to myself was to figure out how to create a static site with html in place of a dynamic site with a few cfm templates. Translated: how to publish a section of my dynamic site as static html files. Sometimes there are benefits to this and sometimes not, but either way to know how to produce the technique could prove useful. I had looked around on the web for solutions to this and did not really like any of the solutions I found, as I thought they lacked elegance and were too complex. So I got to experimenting one day, and stumbled across a technique I finally liked. I hope you may find it useful. If you think about it, the technique can be expanded to become a very sophisticated publishing mechanism for a larger site, but that is beyond the scope of this tutorial.

Objective

Create a static mini html generated site that will allow a user to skim through movie reviews. The links to each review will appear on the left, and the review will appear on the right. Of course this can be anything more simple and if you so desire more complex but in this case my experiment simply used movie-reviews as the theme.

Database

My table in mysql looks like this. I am providing this so you understand the columns mentioned in the code in the query tags.

• MR_ID ( primary key, and movie review id )
• MR_TITLE ( movie review title )
• MR_DATE ( date/time object, when movie review was created )
• MR_REVIEW ( actual movie review )

Templates

This experiment is organized in this manner…

• wwwroot/test/ ( Root folder where the files for this experiment will reside )
    o publish.cfm ( this is the action page with the logic )
    o /includes/
         reviewtemplate.cfm ( template of the html page, this needs to be a cfm page because it has output variables that will be evaluated )
         navinclude.html ( this file will be created by the action page only ONCE and placed in the include folder, it is cfinclude’ed into reviewtemplate.cfm everytime one single html page is dynamically generated by the action page [ publish.cfm ], but because it is an html file it will not require parsing for every single record in the database. The only parsing is just to merely include it as it is a static file, similar to a server side include for static html sites )
    o /publish/
         This is the directory where all the dynamically generated html files

Templates

reviewtemplate.cfm contains the following:

<html>
    <head>
        <title>
<cfoutput>#mr_title# </cfoutput> Movie Review</title>
        <style type="text/css">
            table { border-top: 1px solid #000; border-left: 1px solid #000 }
            table td { padding: 10px; font-size: 12px; font-family: Verdana, Arial, Helvetica, sans-serif; border-right: 1px solid #000; border-bottom: 1px solid #000 }
            table td.label { font-weight: bold; width: 150px; text-align: left; vertical-align: top }
            table td.field { width: 400px; text-align: left; vertical-align: top }
        </style>
    </head>
    <body>
    <table cellspacing="0" cellpadding="10">
        <tr>
            <td valign=
"top" align="left"><cfinclude template="navinclude.html"></td>
            <td valign=
"top" align="left">
            <cfoutput>
            <table cellspacing="0" cellpadding="0">
                <tr>
                    <td colspan=
"2" style="background: lightyellow">#Now()#</td>
                </tr>
                <tr>
                    <td class=
"label">DB Id</td>
                    <td class=
"field">#mr_id#</td>
                </tr>
                <tr>
                    <td class=
"label">Title</td>
                    <td class=
"field"><strong>#mr_title#</strong></td>
                </tr>
                <tr>
                    <td class=
"label">Date</td>
                    <td class=
"field">#DateFormat(mr_date)#</td>
                </tr>
                <tr>
                    <td class=
"label">Review</td>
                    <td class=
"field">#mr_review#</td>
                </tr>
            </table>

            </cfoutput>
            </td>
        </tr>
    </table>
    </body>
</html>

navinclude.html will look like this once its generated:

<a href="../publish.cfm">Go Back and Re-Publish Files</a>

<ul>
    <li>
<a href="2-Fast-2-Furious.html">2 Fast 2 Furious</a></li>
    <li>
<a href="Analyze-That.html">Analyze That</a></li>
    <li>
<a href="Bad-Boys-2.html">Bad Boys 2</a></li>
    <li>
<a href="Bend-It-Like-Beckham.html">Bend It Like Beckham</a></li>
    <li>
<a href="Bruce-Almighty.html">Bruce Almighty</a></li>
    <li>
<a href="Catch-Me-If-You-Can.html">Catch Me If You Can</a></li>
    <li><a href=
"Chicago.html">Chicago</a></li>
    <li>
<a href="Cold-Mountain.html">Cold Mountain</a></li>
    <li>
<a href="Collateral.html">Collateral</a></li>

( continues on for the rest of the records….. )

Finally here is the action page, publish.cfm,

NOTE: I did the replace on the links and file names because I found IIS was not finding the file correctly when browsed too, not sure why this was.

NOTE: The cfflush tag shows the progression. I duplicated this code about 100 times on the same template to see how fast coldfusion could write a few thousand files and I wanted to see the progress as this happened, you do not have to use the cfflush tag.

<cfprocessingdirective suppresswhitespace="yes">
    <cfflush>
    <h5>1. Query Database...</h5>
    <!--- Get Data from database --->
    <cfquery name="review" datasource="databasename">
        SELECT mr_id, mr_title, mr_date, mr_review
         FROM moviereview
        ORDER BY mr_title ASC
    </cfquery>
    <cfflush>
 
   <h5>2. Generate Navigation File...</h5>
    <!--- Generate navigation, write once to a file every typical update --->
    <!--- Instead of using eval we use cfsavecontent and then output that variable to one static html file that will be included in all the dynamically generated html pages --->

    <cfsavecontent variable="links">
        <a href="../publish.cfm">Go Back and Re-Publish Files</a>
        <ul>
        
<cfoutput query="review">
            <!--- Make hyperlinks match generated file names --->
            <cfset linkname = Replace(mr_title, " ", "-", "All")>
            <cfset linkname = Replace(linkname,
":", "", "all")>
            <li><a href="#linkname#.html">#mr_title#</a></li>
        </cfoutput>
        </ul>
    </cfsavecontent>
    <!--- Write nav file for inclusion in generated html documents --->
    <cffile action="write" file="C:\CFusionMX7\wwwroot\test\includes\navinclude.html" output="#links#">
    <cfflush>

    <h5>3. Build html files...</h5>
    <!--- Create html files using query loop --->
    <cfloop query="review">
        <cfsavecontent variable="output">
            <!--- Grab html document template, populate with data from query --->
            <cfinclude template="includes/reviewtemplate.cfm">
        </cfsavecontent>

        <!--- Fix link file names for output --->
        <cfset linkname = Replace(mr_title, " ", "-", "All")>
        <cfset linkname = Replace(linkname,
":", "", "all")>
        
<!--- Write html files for output --->
        <cffile action="write" file="C:\CFusionMX7\wwwroot\test\published\#linkname#.html" output="#output#">
    </cfloop>
    <cfflush>

    <h5>4. Done!!</h5>
    <a href="published/2-Fast-2-Furious.html">Go to reviews</a>
</cfprocessingdirective>

Tips, and Other Ideas

1. You could place this code in coldfusion components.
2. You could separate the ability to edit or update versus push the html file out in a larger project and schedule an action page to run every 30 minutes or whatever time you specify to write out the new files with the updated or edited changes.
3. If your projects are more sophisticated it is easy to look at this code and extend it to be more sophisticated ( like if you had to update different files in other directories at the same time, and create all new navigation includes all in the same pass )

Once again Coldfusion makes what is a tedious task in other languages simple and fast. Just think if your site was not too big you could have a dynamic admin but a dynamically generated static site. This could be beneficial on hosting plans that are shared among multiple websites that have heavy server loads. The possibilities are endless and easily achieved using the power of Coldfusion. I hope at least one person can and will find this tutorial useful.



All ColdFusion Tutorials By Author: Paul Soucy
  • How to Dynamically Generate Static HTML Files Using Coldfusion
    This tutorial shows the user how to create static html files using Coldfusion instead of using dynamic cfm templates. The tutorial illustrates this technique by creating a fictional mini site containing links to movie reviews and the actual movie reviews.
    Author: Paul Soucy
    Views: 8,890
    Posted Date: Tuesday, May 3, 2005