Serving Dynamic HTML Pages


ACI - Documentation Français English German ACI Technical Notes ACI Technical Notes, By Subject Back Previous Next Find

Serving Dynamic HTML Pages

By Hugo Fournier, 4D, Inc. Technical Support

Technical Note 00-36

Technical Notes for Technical Notes for 00-08 August 2000

Introduction


The purpose of this technical note is to demonstrate a simple method for publishing dynamic HTML text pages. The contents of these pages are data-driven and take advantage of 4D as a RDBMS (Relational Database Management System). The solution described here takes advantage of 4D's non-contextual mode, and more specifically utilizes a 4D ACTION in a URL.

Scope


In order to keep this example simple, and to address difficulties in a sequence that manages an easy learning curve, the HTML template we will use will remain fairly simple. The purpose here is to define a simple HTML template and have 4D publish its contents automatically.

The following technical points are addressed:

— Defining a structure that allows you to manage a hierarchical scheme when publishing documents.

— Using 4D ACTION in a URL.

— Managing an HTML template and populating it with data.

— Using SEND HTML BLOB to send the actual HTML code.

Getting Started with the Sample Database


The sample database is configured so that it redirects the links it creates to the 127.0.0.1 local address. If you want to connect from a separate machine, you will need to enter the IP address of the server machine in the existing record of the Templates table.

You can also add data to the Chapters and Paragraphs tables. It will be published and formatted in accordance with the HTML template stored in the Templates table.

The Sample File and its Matching HTML Template


The sample database that is provided with this technical note is designed to publish a document with three hierarchical levels of text: two levels of titles and one level of body text. The data used in this example consists of extracts of the 4D Server documentation, and is to be considered as raw text data.

The end result we aim to achieve will look like:

This HTML page consists of two tables:

— One table that includes the other, and which consists of one row and one column.

— Another table that initially consisted of two rows and two columns. That table is the table whose borders appear in the final document. The other table is not used in this example, but it could be used to display a different background or additional data.

The interface of this HTML document allows the user to select a chapter by clicking its name in the list of chapters on the left. Once clicked, the contents of that chapter are displayed on the right side of the page. The contents are organized in two levels: body text and title.

The data is organized as follows: One chapter includes several subchapters, each of which consists of one single title and, possibly, several paragraphs. The data organization is described this way because it almost tells you what data structure to use: a One table for storing the chapters, and a Many table for storing the chapter's contents.

What additional data do we need to include?

— The server's IP address. Since this example is most likely to be used on local machines or local networks, and since the database needs to return URLs pointing to itself in the HTML contents, an IP address is needed during the assembly of the HTML code.

— The template data. Since we chose to use fully dynamic pages, there is no HTML page stored on disk. All the HTML data will be stored in the database.

These requirements leave us with the following structure:

In the Chapters and Paragraphs tables, Sequence_ID fields were added so you can define a publishing order. The Templates table is used to store the template and IP address. It would be logical to store those in two separate tables, but this example is not designed to use several templates or IP addresses.

Where Do We Go From There?


There are two issues that need to be addressed in conjunction with each other:

— The template needs to be designed according to the result you want to achieve.

This part should be done in any HTML editor and has very little to do with the actual programming of the database. However, you will need to isolate and locate where data needs to be inserted and leave a text string to which you can refer for future replacement.

— You need to implement some code so the 4D database reacts to a specific call through a 4D ACTION, and creates the appropriate HTML.

Creating the Template


In this example, once the final appearance of the HTML documents is reached using fake data, it is necessary to replace that data with a text string that will serve to mark the location where the data will be inserted.

This gives us the following template:

As you can see, there remains only one instance of each paragraph type, each delimited by a specific text string:

— Chapter_Target. This text string marks the location where the chapter title will have to be inserted.

— Body1_Target. This text string marks the location where the chapter subtitle will have to be inserted.

— Body2_Target. This text string marks the location where the subtitle's main text body will have to be inserted.

You surely have already noticed that there is only one instance of each paragraph type. The reason is simple: since you do not know beforehand how many paragraphs will have to be inserted, you will have to let 4D process the template so that there is an adequate number of marker strings to replace. If, in one chapter, there are four matching records in the Paragraphs table and therefore four subtitles with the corresponding body text, you will need four target strings to replace. The same applies to chapter titles.

Before we can insert the HTML template in the database, we need to isolate in the HTML code what the exact strings and corresponding tags to be replaced are:

This gives us:

— Chapter_Target. When we want to replace that string we will actually be replacing: "<p>Chapter_Target</p>"

— Body1_Target. When we want to replace that string we will actually be replacing:

"<p><b><font size="+3">Body1_target</font></b></p>"

The difference between this string and the two others is the inclusion of some font size information.

— Body2_Target. When we want to replace that string we will actually be replacing:

<p>Body2_Target</p>.

Now that the template is set and we know which string to look for, the template is ready to be stored in a text field in the Templates table.

Creating the Code that Manages the HTML Creation


The main problem here is to define what the database needs to do once users click on a chapter title or connect through the IP address of the web server (the first connection):

1) When 4D detects a web connection, the database needs to process the generic template so that there are as many chapter targets as there are chapters to insert. In this case, there should be as many targets as there are records in the Chapters table.

2) Based on the parameter passed to the "Welcome" method through the URL, a selection is created in the Paragraphs table.

3) Based on that selection, 4D creates as many subtitle and text body targets as there are records in the current selection of the Paragraphs table.

4) 4D replaces the target strings with the actual data.

5) 4D sends the actual data to the web browser.

The code in the database breaks down the HTML creation as described above. The sequence is initiated in the "Welcome" method which is either called by the On Web connection Database Method or through a 4D ACTION.

   ALL RECORDS ([Templates])
   MyLastVar := Populate_Gen_Chapters ([Templates]Template)
   
   If (Type ($1) = 5)
         `Is that variable undefined?
      MyLastVar := Substitute_chapters (MyLastVar)
      QUERY ([Chapters]; [Chapters]Title = "4D Server")
      RELATE MANY ([Chapters])
      
      MyLastVar := Populate_Gen_SubChapters (MyLastVar)
      MyLastVar := Substitute_SubChapters (MyLastVar)
   Else 
      MyLastVar := Substitute_chapters (MyLastVar)
      $1 := Replace string ($1; "/"; "")
      QUERY ([Paragraphs]; [Paragraphs]Title = $1)
      MyLastVar := Populate_Gen_SubChapters (MyLastVar)
      MyLastVar := Substitute_SubChapters (MyLastVar)
   End if 
   TEXT TO BLOB (MyLastVar; Myblob; 3)
   SEND HTML BLOB (Myblob; "HTM"; 8)

The main sequence in this method consists of calling four different methods:

"Populate_Gen_Chapters" method

This method replaces the chapter targets by as many targets as the number of records in the Chapters table requires. The idea is to create target text strings, one for each chapter that needs to be inserted. Obviously, for the text target to properly mark its location, a convention needs to be used. In this case, Chapter_Target is replaced by Chapter1_Target … ChapterN_Target, where N is the ordinal number of the chapter title.

In HTML code, it consists of replacing <p>Chapter_Target</p> with <p>Chapter1_Target</p><p>...</p>ChapterN_Target</p>

Once the template has been modified by the "Populate_Gen_Chapters" method, it looks like the following example, which has two records in the Chapters table:

As you can see, only text targets were generated. The next step is to populate the chapter titles with their actual values. This is performed by the following method.

"Substitute_chapters" method

As mentioned above, this method replaces each of the chapter targets with their corresponding value. These replacements are also performed using the Replace string command. However, when it replaces the text targets, that method also creates the URL used for the link of each object. To be able to link back to the database, we need to define those links.

A typical link would look like: <a href="http://IP_Address/4DACTION/MethodName/parameter>ChapterTitle"

Reminders:

1) When used in a URL, a 4DACTION allows you to call a 4D method. Parameters should be passed after the method name, and should be separated by a forward slash.

2) Keep in mind, when using multiple parameters, that they will appear in the $1 variable "as is" with forward slashes between them.

In the example, we want to call the "Welcome" method and pass the name of the chapter as a parameter. This ensures that when users click the link to a specific chapter, that parameter will tell 4D which query to perform.

In the "Substitute_chapters" method, the line of code responsible for creating the needed link is:

   ReplacementString := "Char (34) + "http://" + [Templates]IP_Address
   + "/4DACTION/Welcome/" + Remove_Spaces ([Chapters]Title) + Char (34) + ">"
   + [Chapters]Title + ""

You will notice that the quote characters that should appear in the HTML code have been replaced with Char (34) to avoid any conflict with the syntax of the 4D code itself. This is a common practice when dealing with HTML code.

Once the "Substitute_chapters" method has been executed, the HTML output appears in the browser as:

The links are ready to be used, but no subchapter data has been addressed yet. As with the chapters, the replacement, duplication and substitution of the text targets is performed in two steps.

"Populate_Gen_SubChapters" method

This method is quite similar in principle to the "Populate_Gen_Chapters" method. It creates generic target names for subchapters. It is a little more complicated, since two targets have to be created for each record. Also, it applies only to a selection of records, whereas "Populate_Gen_Chapters" had to address all the records in the Chapters table.

Once it is applied to the template, the template appears in the browser as:

As you can see, it created the generic text targets that will be used for the final data replacement, and left the existing links untouched.

"Substitute_SubChapters" method

This method performs the last step of the HTML creation. It replaces the text targets by data extracted from the current selection in the Paragraphs table. The only specific problem it addresses is the replacement of carriage returns by "end of paragraph" tags (</p>). Those carriage returns are stored in the Description Text field, and they need to be replaced by a tag to provide an effect in HTML similar to a carriage return. This specific problem is addressed by calling the "Remove_Spaces" method.

Once that method is executed, the text variable (MyLastVar) is ready to be stored in a BLOB and sent to the browser.

Note: To store that variable, we used the TEXT TO BLOB command. Do NOT use the VARIABLE TO BLOB command, which is designed for variables that were created from BLOBs.

Finally, when that last command is executed, the browser displays a complete page:

Summary


This technical note demonstrated the creation of a simple database that can create dynamic HTML pages. Although it remains simple, it demonstrates the use of 4DACTION in a URL, the basics of string replacement, and how a simple relational structure can match the structure of hierarchical HTML documents.


ACI - Documentation Français English German ACI Technical Notes ACI Technical Notes, By Subject Back Previous Next Find