Previous     Contents     Index     DocHome     Next     
iPlanet Application Server 6.0 Programmer's Guide (C++)



Chapter 7   Working with Templates


This chapter describes templates, which are text files that can be merged with dynamic data to produce formatted output.

The following topics are included in this chapter:



What are Templates?

Your application can include two types of templates, depending on the types of results being returned from the AppLogic objects in the application:

  • GXML templates are used to return self-describing, formatted data to other AppLogics. GXML templates are used only when you are using the EvalOutput( ) method to return client-independent results.

  • HTML templates are used to return HTML pages to Web browsers. HTML templates are used when you are using the EvalTemplate( ) method to explicitly return HTML results, or when you are using EvalOutput( ) to return client-independent results and the client happens to be a Web browser.


What is a GXML Template?

A GXML template is a definition for a dynamically-generated set of output data. GXML templates are made up of special GX markup tags that specify how dynamic data is to be sent back to the client.

AppLogics use GXML templates in conjunction with the EvalOutput( ) method to return client-independent results. Data retrieved from a database or other data source at runtime is sent back to the client in a self-describing stream of output. This self-describing data stream is created according to the specifications in the GXML template. The client receiving these results then processes the output and puts it to use in reports, calculations, UI controls, or any desired task.


What is an HTML Template?

An HTML template is a definition for a dynamically-generated HTML page. HTML templates are similar to HTML pages, but they also include special GX markup tags that are specific to iPlanet Application Server applications. The GX markup tags in the template specify how dynamic data is merged with the page. Dynamic data is the added feature that makes a page an HTML template rather than just an ordinary, static HTML page.

AppLogic objects use HTML templates to format their output and present dynamically generated HTML pages to a Web browser. Data retrieved from a database or other data source at runtime is merged with the HTML template to create one of the following types of output:

  • The data can be displayed in the HTML page to present a database report. For example, a customer might request a report of currently available products and prices.

  • The data can be used to dynamically modify the HTML page itself, changing the HTML tags, images, sounds, applets, or other features. For example, you might dynamically change which commands or AppLogic objects the user can choose from next by modifying the returned URL.

An HTML template can contain static elements, such as introductory text and logos. Its GX markup tags provide the placeholders in which a variety of data values can be used.

HTML templates provide a modular technique for designing HTML pages. AppLogics can share the same HTML templates, and the templates can easily be updated or translated and localized without affecting application code and business rules.


Example: Report
In a sales support application, a user's request for customer sales data causes an AppLogic to get the latest data from the database. The AppLogic merges the data with an HTML template and returns a sales report to the user. The sales report is an HTML page with standard headings, graphics, and other elements merged with the dynamic sales data.


Example: Dynamically Modified HTML Tag
An AppLogic queries a geographic database to create a report about the countries of the world. The data includes country names and populations. The country name is used to dynamically modify the filename in an HTML <img> tag inside a loop, so that a different illustration is displayed for each country.


Example: Dynamically Populated Form
A chain of hardware stores has an online inquiry application in which users can get information about store locations. The user types a home address into a form, then submits the form. The application looks up the stores in the customer's home town, then uses an HTML template to create a form that contains a list box with the street addresses of the selected stores. The user can then select one store and submit a request for more information about that store.


Parts of an HTML Template

Like any HTML page, an HTML template can include features implemented using the normal HTML markup tags, such as the following:

  • Text and graphics

  • Interactive features such as buttons and hyperlinks

  • Calls to applets

By using the GX markup tags, an HTML template can also include the following:


Runtime Behavior of HTML Templates

The following illustration and list summarize how an HTML template is typically used at runtime.



  1. A user makes a request through a Web browser.

  2. In response to the request, an AppLogic runs. The AppLogic specifies a query and passes the query and the name of an HTML template file to iPlanet Application Server's Template Engine.

  3. The Template Engine queries the database and retrieves dynamic data.

  4. The Template Engine merges the data with the HTML template and streams the resulting dynamically-generated HTML page to the Web browser.



How to Write a GXML Template

To create a GXML template, you can use either of the following techniques:

By convention, GXML templates are kept in one of the following directories:

  • [HTTPDIR]/GXApp/ProjectName/Templates, where [HTTPDIR] is the document root directory of your HTTP server and ProjectName is the name of your application or package.

  • [GXINSTALL]/Apps/ProjectName/Templates, where [GXINSTALL] is the directory in which your iPlanet Application Server software is installed.

In addition, administrators can specify a search path for templates. For more information, see the Administration and Deployment Guide.


Converting HTML Templates to GXML Templates

You can convert an existing HTML template into a GXML template by using the command-line utility khtml2gxml. This tool removes all HTML from the template, leaving only the GX markup tags.

To convert HTML to GXML

Type the following command at the command line prompt:

khtml2gxml filename.html

A new GXML template file, filename.gxml, is created.



How to Write an HTML Template



To write HTML templates, you can use iPlanet Application Builder. This tool gives you a head start on creating some commonly-used types of templates.

You can also code the HTML tags yourself, using any text editor or HTML authoring tool. In either case, you need to understand the GX markup tags.

For more information, see GX Markup Tag Syntax.

By convention, HTML templates are kept in one of the following directories:

  • [HTTPDIR]/GXApp/ProjectName/Templates, where [HTTPDIR] is the document root directory of your HTTP server and ProjectName is the name of your application or package.

  • [GXINSTALL]/Apps/ProjectName/Templates, where [GXINSTALL] is the directory in which your iPlanet Application Server software is installed.



Calling an AppLogic Object From an HTML Page

When a user makes an action request from a Web browser, such as by clicking a button on an HTML page, iPlanet Application Server runs the appropriate AppLogic object to handle the request. To create an HTML page that calls an AppLogic, you embed a special URL link in the HTML page. For example, the URL can be activated through a hyperlink or a button. Use the normal HTML technique for linking to a URL, and use a URL with one of the following syntaxes:

To call the AppLogic using a GUID, use the following syntax (all on one line):

[http://www.company.com]/cgi-bin/gx.cgi/

   GUIDGX-{E5CA1000-6EEE-11cf-96FD-0020AFED9A65}[?]

   [param=value[&paramN=valueN] ...]

To call an AppLogic by name, use the following syntax (all on one line):

[http://www.company.com]/cgi-bin/gx.cgi/AppLogicName[?]

   [param=value[&paramN=valueN] ...]

  • The URL prefix (http://www.company.com) is required if the URL is used in a hyperlink.

  • The code cgi-bin/gx.cgi runs the gx.cgi program, which forwards the request to the iPlanet Application Server. The server loads and runs the AppLogic registered with the given name or GUID. If you are using a Netscape Web connector, such as NSAPI or ISAPI, the connector automatically intercepts any gx.cgi requests. Thus you can write your application with a CGI environment and deploy in an NSAPI environment.

  • In the first syntax, the GUIDGX- prefix indicates that a GUID is the next part of the URL.

  • In the first syntax, the last part of the URL, between and including the brace characters { }, is the GUID that identifies which AppLogic to run.

  • The question mark is required if parameters are included in the URL.

  • You can optionally specify one or more named parameters at the end of the URL.

Use these special URLs throughout your application's HTML interface, wherever you want to run an AppLogic in response to a user clicking a button or other control.


Examples
The following HTML form, from the Online Bank sample application, runs the FindCust AppLogic. The AppLogic request is coded in the action attribute. When the user clicks the Search button, the Web browser forwards this request to the Web server. The Web server, in turn, sends the request to iPlanet Application Server. If an AppLogic has been compiled and registered with this name before the request is received, iPlanet Application Server runs that AppLogic.

<FORM method="POST" action="/cgi-bin/gx.cgi/AppLogic+FindCust">

<!-- Body of HTML form here -->

<input type="submit" name="go" value="Search">

The following portion of an HTML page shows how to call an AppLogic from a hyperlink:

<a href="/cgi-bin/gx.cgi/AppLogic+CShowNewCustPage">

Add New Customer </a>



GX Markup Tag Syntax



The GX markup tag is a matched tag. Every opening marker, %gx%, must be matched by a closing marker, %/gx%. The syntax of the GX markup tag is as follows:

%gx {TagAttributes} %

   [textBlock]

%/gx%

You can also use angle brackets instead of percent signs, as follows:

<gx {TagAttributes} >

   [textBlock]

</gx>


TextBlock

The TextBlock portion of a GX markup tag can include the following:

  • Plain text

  • HTML tags

  • Nested GX markup tags

For example, in the following GX markup tag, the second line is the text block, including both a nested GX markup tag and an HTML tag (<br>):

%gx type=tile id=CONTINENT%

   %gx type=cell id=CONTINENT.NAME%%/gx%<br>

%/gx%

In the following GX markup tag, the second line is the text block, including both plain text and an HTML tag (<img>):

%gx type=replace id=CONTINENT.NAME value=PlaceHolder%

   Selected Continent: <img src="images/PlaceHolder.gif">

   %/gx%


TagAttributes

The TagAttributes portion of a GX markup tag can be a combination of the following items:

The rest of this section describes each item in more detail. You can specify these items in any order within the GX markup tag.


type=TypeCode

Required. Indicates what action is to be performed for this tag when an AppLogic merges data with the template. The TypeCode is one of the following:


Cell
Replaces the entire GX marker, from %gx% to %/gx%, with a dynamic data value. Used with the id attribute, which specifies a field in the result set that contains the dynamic value to be used. For example:

%gx type=cell id=CTY.sumsales%%/gx%

For a more detailed example, see Using the Cell Attribute in a GX Markup Tag.


Tile
Repeats the TextBlock. The tile tag can be used in two ways: repeating a fixed number of times, or repeating for each row in a result set. When you use nested tile tags along with a hierarchical query, the result is a grouped master-detail report.

To repeat the TextBlock a specified number of times, use the min attribute to set the number. Do not use the id attribute. For example:

%gx type=tile min=5% . . . %/gx%

To repeat the TextBlock for every row in a query's result set, use the id attribute to specify the name of the query. A query is given a name when you add a flat query to a hierarchical query, or when you name a query in a query file. For more information about using the id attribute in this way, see Meaning Of id when Type is Tile.

You can also use the max attribute, which specifies a limit on how many times the tile can be repeated. This is useful for limiting the length of the generated HTML page if the size of the result set is potentially large. For example:

%gx type=tile id=COUNTRY max=1000% . . . %/gx%

For more detailed examples of both techniques, see Using the Tile Attribute in a GX Markup Tag.


Replace
Searches TextBlock for a string and substitutes a dynamic data value for that string. Used with the value attribute, which specifies the search string, and with the id attribute, which specifies where to find the replacement value. For example:

%gx type=replace id=CUST.name value=CustName%

   Dear CustName: %/gx%

For a more detailed example, see Using the Replace Attribute in a GX Markup Tag.


Include
Replaces TextBlock with HTML output created by evaluating another template. Used with the id attribute, which specifies the path of the template. For example:

%gx type=include

   id="GXApp/OnlineBooks/Templates/header1.html"%

For a more detailed example, see Using the Include Attribute in a GX Markup Tag.

Do not specify the same template name as the current template. A template cannot include itself.


User-Defined Tag
Performs a user-defined action. For example, you could write the following GX markup tag:

%gx type=trigger name=Clock arg1=hello%%/gx%

To use this type of tag, you must write a customized template map class. When the Template Engine encounters an unknown type of GX tag, it calls the template map's Get( ) method and passes it the unknown tag. For example, the trigger tag shown above results in the following string being passed to Get( ):

trigger:name="Clock";arg1="hello"

The Get( ) method in your template map subclass must be able to parse and respond to this string.

For more information about implementing a custom GX markup tag, see Creating a User-Defined Tag.


id=Name

The meaning of the id attribute varies depending on the value of the type attribute. The id attribute is required in all GX markup tags, except when the min attribute is used to repeat a tile a specified number of times.


Meaning Of id when Type is Tile
When the type attribute is tile, the id attribute specifies the name of a query. The marker's TextBlock repeats for the number of rows in the query's result set. For an example, see Using the Tile Attribute in a GX Markup Tag.

The value you can use in the id attribute is set when a query is added to a hierarchical query, or when you name a query in a query file. For example, suppose the AppLogic contains the following code, which adds a query named CTY to a hierarchical query:

pHq->AddQuery(pQuery, pConn, "CTY", "", "");

The HTML template that displays data from this query can use the name CTY in the id attribute of a tile tag. For example

%gx type=tile id=CTY%

This is how tile tags are normally implemented. However, if you are using the min attribute to control the number of times the tile repeats, you do not use the id attribute.


Meaning of id when Type is Cell or Replace
When the type attribute is cell or replace, the id attribute specifies a field in the result set. The field contains the data value to be displayed. If the AppLogic is using a hierarchical query, the field is specified using dot notation. A query name (derived in the same way as that used with the tile tag) comes before the dot, and a column name or alias comes after the dot. For example:

%gx type=cell id=CTY.sumsales%%/gx%

For a more detailed example, see Using the Cell Attribute in a GX Markup Tag.

The id attribute in a cell tag can include a format string to specify a numeric or character format.

For more information, see Formatting Data in a Cell Tag.

If the data specified in the id attribute is not found in the result set, the static text, if any, in the TextBlock is displayed instead of the dynamic data that would have replaced it. For example, in the following tile tag, the text Customer name here appears if the custName field is not found or is empty:

%gx type=tile id=CUST%

   %gx type=cell id=CUST.custName%Customer name here

   %/gx%<br>

%/gx%


Meaning of id when Type is Include
When the type attribute is include, the id attribute specifies the path of an HTML template. You can use a literal path enclosed in double quotes or a field in a result set. For example:

%gx type=include

   id="GXApp/OnlineBooks/Templates/header1.html"%

For a more detailed example, see Using the Include Attribute in a GX Markup Tag.


visible={True | False}

Optional. Determines whether the portion of the page enclosed by the GX markup tag appears in the final HTML page that results when an AppLogic merges data with the template. Default is True. Set to False to hide a marked-off portion of the page, including nested GX tags and dynamic data.


min=MinVal

Optional. Use only when the type attribute is tile. Specifies the smallest number of times the tile can be repeated when an AppLogic merges data with the template. When used alone, specifies a static number of times for the tile to repeat. Default is 0.


max=MaxVal

Optional. Use only when the type attribute is tile. Specifies the greatest number of times the tile can be repeated. Default is 232. For an example, see Using the Tile Attribute in a GX Markup Tag.


value=ReplaceVal

Required when the type attribute is replace. Specifies a string to search for in TextBlock. This string is replaced with dynamic data when an AppLogic merges data with the template. For an example, see Using the Replace Attribute in a GX Markup Tag.


Using the Cell Attribute in a GX Markup Tag

The cell type of GX markup tag is the lowest-level building block in a report-style HTML template. Each cell tag, including any TextBlock, is replaced by a single value from one row of data from the database. For example, suppose you want to generate a dynamic sales letter from a customer database. Your HTML template could include the following cell tag:

Dear %gx type=cell id=CustName%

   Customer name here   %/gx%,<br>

Thank you for buying the SmartSurf 2000 Web robot . . .

When an AppLogic merges data with this template, the entire text from %gx% to %/gx%, including Customer name here, is replaced with a customer name from the database field CustName. For example:

Dear M. Smith,<br>

Thank you for buying the SmartSurf 2000 Web robot . . .


Using Cell with Tile

The cell tag is commonly used in combination with the tile tag, which causes the cell to repeat for a group of data rows. The following example contains both tile and cell tags. The cell tag is a placeholder for the individual continent name. The tile tag causes the cell tag to be repeated for all the continents in the database.

%gx type=tile id=CONTINENT%

   %gx type=cell id=CONTINENT.NAME%%/gx%<br>

%/gx%

Remember that all text inside the cell tag is deleted and replaced with dynamic data. Take care that the cell tag does not contain text you want to appear in the finished HTML page. In the previous example, the HTML tag <br> is outside the cell tag, so it is passed through without change. If the <br> were accidentally placed before the %/gx% that marks the end of the cell tag, the <br> would be deleted.

When an AppLogic merges data with this HTML template, text like the following replaces the GX tags:

AFRICA<br>

ANTARCTICA<br>

ASIA<br>

AUSTRALIA<br>

EUROPE<br>

N_AMERICA<br>

OCEANIA<br>

S_AMERICA<br>

You can include several cell tags within one tile tag. For example, the following tags print two fields, the county name and number of customers, for each county in a state. Because the max attribute is set, the tag will not generate entries for more than 100 counties in a single state.

%gx type=tile id=DETAILS MAX=100%

   %gx type=cell id=DETAILS.COUNTYNAM%%/gx%

   %gx type=cell id=DETAILS.CUSTS%%/gx%<br>

%/gx%

When an AppLogic merges data with this HTML template, text like the following replaces the tags:

San Mateo  100<br>

Santa Clara  300<br>

Sonoma  400<br>


Formatting Data in a Cell Tag

You can include a format specification in the id attribute of a cell tag. To do so, place the attribute value in quotes, place a comma after the data field name, and call the format( ) function. You use this function to specify a format string, which determines how the data appears in the HTML output page.

For example, the following cell tag specifies that the sales figure is to start with a dollar sign, include a thousands separator, and show two digits to the right of the decimal point:

%gx type=cell id="CTY.sumsales, format($0,000.00)"%%/gx%

The argument to the format( ) function is a format string. This string is made up of ordinary text, such as the dollar sign, and special characters that influence how data is presented. The following tables describe the special characters you can use in a format string. The set of characters you can use varies depending on the type of data. You cannot mix characters from the different types in a single format string.




Character

Meaning

Example Data

Example String

Example Result

#  

Unfilled digit placeholder. Replaced by numeric digits in the data.

If the data to format has fewer digits than the format string, the empty places are not filled. The output can be shorter than the format string.  

679.649

700

 

#####.##

$#,###.00  

679.64

$700.00

 

0  

Zero-filled digit placeholder. Replaced by numeric digits in the data.

If the data to format has fewer digits than the format string, the empty places are filled with zeros. The output is always at least as long as the format string.

When placed to right of decimal point, indicates precision. Data is rounded if necessary.  

679.649

679.649

700

 

0000.00

00###

$000.00  

0679.65

00679

$700.00  

,  

Thousands separator.

A separator character will appear between every three digits to the left of the decimal point in the output data.  

1234  

0,000  

1,234  

.  

Decimal separator.

A decimal point character will appear between the whole and fractional parts of the output data.  

679.649

700  

000.00

$#,###.00  

679.65

$700.00  

;  

Separates a pair of formats. The first format is used for positive numbers, the second for negative numbers.  

23

-66  

##;(##)

##;(##)  

23

(66)  

Literals such as $ + - ( ) and space characters  

Any character in the format string that is not a special character will appear in the output data exactly as typed. If using parentheses, always use matched pairs.  

5552365

69100

123

 

###-####

$0,000

0 0 0  

555-2365

$69,100

1 2 3  

Numeric Format Characters"> Numeric Format Characters


Date/Time Format Characters




Character

Meaning

Example Data

Example String

Example Result

D  

Day of the month, with no leading zero.  

1/1/2020  

M-D-YY  

1-1-20  

DD  

Day of the month, with leading zero.  

1/1/2020  

MM-DD-YY  

01-01-20  

DDD  

Day of the week, abbreviated.  

7/4/1996  

DDD  

Thu  

DDDD  

Full day of the week.  

7/4/1996  

DDDD  

Thursday  

M  

Number of the month, with no leading zero.  

1/1/2020  

M-D-YY  

1-1-20  

MM  

Number of the month, with leading zero.  

1/1/2020  

MM-DD-YY  

01-01-20  

MMM  

Name of the month, abbreviated.  

1/1/2020  

MMM  

Jan  

MMMM  

Full name of the month.  

1/1/2020  

MMMM  

January  

Y  

Number of the day in the year (1-366).  

1/1/2020  

Y  

1  

YY  

Last 2 digits of the year.  

1/1/2020  

M-D-YY  

1-1-20  

YYY or YYYY  

All 4 digits of the year.  

1/1/2020  

M-D-YYYY  

1-1-2020  

h  

Hour from 1-12, with no leading zero.  

8:05 pm  

h:mm  

8:05  

hh  

Hour from 1-12, with leading zero.  

8:05 pm  

hh:mm  

08:05  

H  

Hour from 1-24, with no leading zero.  

8:05 pm  

H:mm  

20:05  

HH  

Hour from 1-24, with leading zero.  

3:00 am  

HH:mm  

03:00  

m  

Minute, with no leading zero.  

3:09 am  

h:m  

3:9  

mm  

Minute, with leading zero.  

3:09 am  

h:mm  

3:09  

s  

Seconds, with no leading zero.  

3:09 am  

h:m:s  

3:9:0  

ss  

Seconds, with leading zero.  

5:07:02 am  

hh:mm:ss  

05:07:02  

AM/PM  

Adds letters AM or PM after the date/time data to indicate morning or afternoon/evening hours.  

5:07:02 am  

h:mm AM/PM  

5:07 AM  

Literals such as / - : and space characters  

Any character in the format string that is not a special character will appear in the output data exactly as typed.  

1/1/2020

8:05 am  

m-d-yy

h:m:s  

1-1-20

8:5:0  


Using the Tile Attribute in a GX Markup Tag

The tile type of GX markup tag can be used to repeat portions of an HTML template in two ways:


Repeating for Each Row in a Result Set

The tile tag is typically used to nest levels of data in an HTML template for a grouped report. There is no practical limit to the levels of nesting. Each tile tag specifies a group of data rows. The text block nested in the tile tag is repeated once for each row in the group. The group of data rows is the result set from one of the queries in a hierarchical query object.

In a grouped report, the tile tag is used in combination with the cell tag. The tile tag specifies the repeating, and the cell tag specifies what data value to display for each repetition.

The following example shows two levels of nested tags:

%gx type=tile id=CONTINENT%

   - %gx type=cell id=CONTINENT.NAME%%/gx%<br>

   %gx type=tile id=COUNTRY%

      --- %gx type=cell id=COUNTRY.NAME%%/gx%<br>

   %/gx%

%/gx%

When an AppLogic merges data with this HTML template, text like the following replaces the tags:

- ASIA<br>

--- China<br>

--- Japan<br>

- EUROPE<br>

--- France<br>

--- Germany<br>

- N_AMERICA<br>

--- Canada<br>

--- Mexico<br>


Repeating a Specified Number of Times

You can use the min attribute to repeat a tile a specified number of times. For example, the following example repeats a decorative graphic five times:

%gx type=tile min=5%

   <IMG SRC="/GXApp/MyApp/Images/smiley.gif" ><br>

%/gx%

When an AppLogic merges data with this HTML template, text like the following replaces the tags:

<IMG SRC="/GXApp/MyApp/Images/smiley.gif" ><br>

<IMG SRC="/GXApp/MyApp/Images/smiley.gif" ><br>

<IMG SRC="/GXApp/MyApp/Images/smiley.gif" ><br>

<IMG SRC="/GXApp/MyApp/Images/smiley.gif" ><br>

<IMG SRC="/GXApp/MyApp/Images/smiley.gif" ><br>


Using the Replace Attribute in a GX Markup Tag

The replace type of GX markup tag is used to dynamically modify part of the text block immediately following the GX tag. You can use the replace tag to dynamically modify HTML tags. Each replace tag specifies a string to search for in the text block and a field from which to retrieve the dynamic replacement value.

The field referred to in a replace tag can be either a database field or a template map field. For more information about template maps, see Using a Template Map.

The following example uses the replace tag to modify an illustration. The HTML tag <img> specifies the filename of an illustration:

%gx type=replace id=CONTINENT.NAME value=PlaceHolder%

   <img src="images/PlaceHolder.gif">

%/gx%

To make this tag more interesting, consider what happens if it is placed inside a tile tag. In the following example, the illustration is repeated for each data row in the CONTINENT query's result set. The HTML tag <img> is displayed once for each data row. The GX replace tag dynamically changes the filename each time the text repeats, so that a different illustration is displayed for each continent.

%gx type=tile id=CONTINENT%

   %gx type=replace id=CONTINENT.NAME value=PlaceHolder%

   <img src="images/PlaceHolder.gif">

   %/gx%

%/gx%

When an AppLogic merges data with this HTML template, text like the following replaces the tags:

<img src="images/ASIA.gif">

<img src="images/EUROPE.gif">

<img src="images/N_AMERICA.gif">


Using the Include Attribute in a GX Markup Tag

The include type of GX markup tag is used to insert output from another template into the current template. For example, you can use the include tag to add commonly-used elements such as headers and footers. You can maintain a library of reusable HTML templates for such tasks to avoid repetitive HTML coding.

Each include tag specifies the pathname of an external template. The included template is merged with the same result set being used for the calling template.

The following examples use the include tag to insert a header. In the first example, a literal path is given for the template file:

%gx type=include

   id="/GXApp/OnlineBooks/Templates/header1.html"%

   Text block to be replaced by output from header1.html

%/gx%

In the second example, a field from a result set is used to create a dynamic path for the template file.

%gx type=include id=CUSTOMER.Preferred_Header%

   Text block to be replaced by output from a template

%/gx%

When an AppLogic merges data with the HTML template that contains one of these tags, the tag is replaced with the output from the included template. The effect is that the AppLogic merges data with several HTML templates using one result set.


Creating a User-Defined Tag

Instead of using one of the predefined types of GX markup tag, such as tile or include, you can use the GX markup syntax to write your own customized tag. Use the type attribute to give the tag a name, and follow it with other attributes that you name and define. For example, you could write the following GX markup tag:

%gx type=trigger name=Clock arg1=hello%Default text%/gx%

To use this type of tag, you must write a customized template map class (that is, subclass the GXTemplateMapBasic class and override the Get( ) method). When the Template Engine encounters an unknown type of GX tag, it calls the template map's Get( ) method and passes the tag attributes in the following format:

userDefinedType:attr1="val1";attr2="val2"

For example, the trigger tag shown above results in the following string being passed to Get( ):

trigger:name="Clock";arg1="hello"

The code you write when you override Get( ) in your subclass must be able to parse and respond to this string. In the simplest case, your Get( ) method can return a null string, in which case the system defaults to using the text block of the gx tag. In the above example, if Get( ) returns a null string, the system replaces the gx tags with Default text.

For more information about subclassing GXTemplateMapBasic, see Using Your Own Template Map Class for Special Processing.



Using a Template Map



A template map is an object that maps fields in a template to the data used to replace those fields. Template maps are instances of the GXTemplateMapBasic class.

A template map is useful when the template uses data from:

  • Multiple data sources with different column names

  • A data source whose schema changes over time

  • Dynamic calculations made at runtime

  • Memory-based data sources defined using an implementation of theIGXTemplateData interface, such as the GXTemplateDataBasic class in the iPlanet Application Server Foundation Class Library.

A template map is useful when the template refers to fields in a particular database, and you want to use the same template with data from another database in which the field names are different. Typically, this occurs when you move from a test database to a production database.

With a template map, you can assign values to special placeholders that will be evaluated at runtime. For example, you can use a placeholder to indicate where you want the current date to appear. You can use these placeholders anywhere you would use database field names inside a GX markup tag. These placeholders need not be preceded by the dollar sign.

You can also use a template map to link column names in a table to field names that you have used in a template. A template map allows your application to use the same template file with data from different data sources.

For example, an application might obtain invoice information from several accounting databases with slight variations in the name of the invoice number column (such as invNum, InvoiceNumber, invId, and so on). With a template map, you can simply change the links between table columns and template fields without rewriting your queries.

To ensure that the template map works, the two database schemas must be the same except for the field names. Also, each field name that is to be mapped must be preceded by a dollar sign ($) in the template.

A single template map can contain values for both placeholders and fields. When data is merged with a template, iPlanet Application Server uses the template map to find the meaning of each field name or placeholder in the template. For example, the following lines from an HTML template contain a placeholder, CURDATE, and a field name, CUST.custname.

%gx type=cell id=CURDATE%%/gx% <br>

Dear %gx type=cell id=$CUST.custname% :

To construct a template map

  1. Instantiate an object from the GXTemplateMapBasic class. For example:

       GXTemplateMapBasic *map;

       map = GXCreateTemplateMapBasic();

    Use the Put( ) method to specify the field name pairs or placeholder and value pairs. The first item in each pair is the field name or placeholder used in the HTML template. For example:

       IGXBuffer *buffer;

       buffer = GXCreateBufferFromString(curr_time):

       map.put("CURTIME", buffer);

    You can place the Put( ) method call inside a loop to construct the template map iteratively. For example, you could use this technique to read the map from a file line by line.

  2. Pass the template map to EvalTemplate( ) or EvalOutput( ). For example:

       result = EvalTemplate("template.html", data, map);


Example
The following code constructs a template map for the following three items in an HTML template called template.html:

  • The placeholder LOGIN is mapped to the value of the login parameter, which is one of the AppLogic's input parameters.

  • The placeholder CURTIME is mapped to a function call which evaluates the current time at the moment the HTML template is merged with data.

  • The database field name STATES.state is mapped to the new field name ST.name. In the HTML template, the original field name is preceded by a dollar sign ($STATES.state).

    char login[256];

    m_pValIn->GetValString("login", login, sizeof(login));

    GXTemplateMapBasic *map;

    map = GXCreateTemplateMapBasic();

    IGXBuffer *buffer;

    buffer = GXCreateBufferFromString(login):

    map.put("LOGIN", buffer);

    buffer->Release();

    buffer = GXCreateBufferFromString(curr_time):

    map.put("CURTIME", buffer);

    buffer->Release();

    buffer = GXCreateBufferFromString("ST.name"):

    map.put("$STATES", buffer);

    buffer->Release();

    HRESULT hr;

    result = EvalTemplate("template.html", data, map);

    map->Release();

The following lines from the HTML template show how these mapped items appear in the template:

User %gx type=cell id=LOGIN%%/gx%

accessed the system at %gx type=cell id=CURTIME%%/gx%

from the following state:

%gx type=cell id=$STATES.state%%/gx%


Using Your Own Template Map Class for Special Processing

A template map is an object instantiated from any class that implements the IGXTemplateMap interface. The iPlanet Application Server Foundation Class Library provides one such class, called the GXTemplateMapBasic class. You can also implement your own template mapping class.

The simplest technique for implementing your own template mapping class is to subclass GXTemplateMapBasic and override the Get( ) method. By doing so, you gain the opportunity to run your own code as part of the template generation process. This is a useful technique for providing special template map processing that is specific to your application.

For example, you can perform the following types of special processing:

  • Filter data from the database before allowing the Template Engine to merge the data with the template. This technique is illustrated in the example code later in this section.

  • Perform special character formatting.

  • Add counters.

  • Insert large, dynamically generated HTML fragments into an output HTML page.

  • Evaluate placeholders multiple times per template. The default implementation of Get( ) in the GXTemplateMapBasic class evaluates the placeholders just once for the entire template.

    Suppose the placeholder CURTIME is mapped to a function that returns the current time. When you set the time by calling Put( ) in the GXTemplateMapBasic class, the time is calculated once, and if CURTIME appears in several places in the template, the same time is printed in each place. Instead, you might want to re-evaluate the placeholder each time it is encountered in the template, so you can implement the Get( ) method in your template map subclass to recalculate CURTIME every time it is called.


Example
The following example from an include file (templatemap.h) shows deriving a template map class (MyTemplateMap) from the GXTemplateMapBasic class. It also declares two overloaded versions of the Put( ) method.

The syntax of the first Put( ) method is identical to the Put( ) method in the parent GXTemplateMapBasic class. The syntax of the second Put( ) method accepts a string parameter (LPSTR) instead of the IGXBuffer object.

class MyTemplateMap : public GXTemplateMapBasic {

public:

MyTemplateMap();

virtual ~MyTemplateMap();

STDMETHOD(Put) (LPSTR szKey, IGXBuffer *pBuff);

STDMETHOD(Put) (LPSTR szKey, LPSTR szValue);

};

The following sample code, from a program file (templatemap.cpp), shows the definitions of the Put( ) methods in the MyTemplateMap class. The first version merely calls the Put( ) method in the parent GXTemplateMapBasic class. The second version copies the szValue string parameter to a newly-created IGXBuffer, then calls the first version of the Put( ) method.

MyTemplateMap::MyTemplateMap()

{

}

MyTemplateMap::~MyTemplateMap()

{

}

// Adds a mapping to a template map

STDMETHODIMP

MyTemplateMap::Put(LPSTR szKey, IGXBuffer *pBuff)

{

return GXTemplateMapBasic::Put(szKey, pBuff);

}

// Adds a mapping to a template map

STDMETHODIMP

MyTemplateMap::Put(LPSTR szKey, LPSTR szValue)

{

   if (!szKey || !szValue) return GXE_INVALID_ARG;

   // Create an IGXBuffer object

   IGXBuffer *pBuff = GXCreateBufferFromString(szValue);

   if (!pBuff) return GXE_ERROR;

   // Call the first Put() version

   hr = Put(szKey, pBuff);

   pBuff->Release();

   }

   return hr;

}



Constructing a Hierarchical Result Set with GXTemplateDataBasic



Normally, you use EvalTemplate( ) or EvalOutput( ) with the result set from a hierarchical query. You pass a hierarchical query object and the path to a template as parameters to the method, which then runs the query and merges the hierarchical result set with the template automatically.

However, you can bypass this automatic procedure and construct a hierarchical result set programmatically, rather than running a query to get the result set. In this way, you can pass data that is from a source other than a database.

For example, the AppLogic might display a list of numbers generated from a formula, or it might display a list of processors available on the server machine and their CPU loads.

To implement a hierarchical result set

  1. Create an instance of the GXTemplateDataBasic class for the first parent level of data in the hierarchy.

  2. Create another instance of GXTemplateDataBasic for a group of data at the child level.

  3. Call the child GXTemplateDataBasic object's RowAppend( ) method one or more times to specify the data in the first group.

  4. Call the parent GXTemplateDataBasic object's RowAppend( ) method to add a row for the child GXTemplateDataBasic object.

  5. Call the parent GXTemplateDataBasic object's GroupAppend( ) method to add the child group of data.

  6. Repeat Step 2 through Step 5 for each group of data in the result set.

  7. After constructing the GXTemplateDataBasic object, pass it to EvalTemplate( ) or EvalOutput( ) instead of passing in the name of a hierarchical query. Each of these methods provides an alternative syntax for this purpose.


Examples
The following code constructs a flat result set with a single level of data:

GXTemplateDataBasic *tdbSalesRev;

tdbSalesRev = GXCreateTemplateDataBasic("salesOffices");

tdbSalesRev->RowAppend("office=New York;revenue=150M");

tdbSalesRev->RowAppend("office=Hong Kong;revenue=130M");

tdbSalesRev->RowAppend("office=Singapore;revenue=105M");

// Use tdbSalesRev, like with EvalTemplate...

tdbSalesRev->Release();

The following code constructs a hierarchical result set with two child levels of data, one for Asia and one for Europe:

/* Create Data Object */

GXTemplateDataBasic *tdbContinents;

tdbContinents = GXCreateTemplateDataBasic("continents");

/* Create the Asia group */

GXTemplateDataBasic *tdbAsia;

tdbAsia = GXCreateTemplateDataBasic("countries");

tdbAsia->RowAppend("country=China;currency=yuan");

tdbAsia->RowAppend("country=Japan;currency=yen");

tdbAsia->RowAppend("country=South Korea;currency=won");

tdbContinents->RowAppend("name=Asia");

/* Link child records to continents group */

tdbContinents->GroupAppend(tdbAsia);

/* Create the Europe group */

GXTemplateDataBasic *tdbEurope;

tdbEurope = GXCreateTemplateDataBasic("countries");

tdbEurope->RowAppend("country=France;currency=franc");

tdbEurope->RowAppend("country=Germany;

   currency=deutsche mark");

tdbEurope->RowAppend("country=Italy;currency=lire");

tdbContinents->RowAppend("name=Europe");

/* Link child records to continents group */

tdbContinents->GroupAppend(tdbEurope);

EvalTemplate("salesByContinent.html", tdbContinents,

   NULL, NULL, NULL);

tdbContinents->Release();

tdbEurope->Release();

tdbAsia->Release();


Improving Performance When Using GXTemplateDataBasic

If you are using an IGXTemplateData object, such as GXTemplateDataBasic, as the source of data for a call to EvalTemplate( ) or EvalOutput( ), you can increase the perceived performance of the call by using the following technique. Instead of populating the IGXTemplateData object by calling RowAppend( ) repeatedly, implement the IGXTemplateData interface yourself and call EvalTemplate( ) or EvalOutput( ) much earlier in the AppLogic code. In this way, the Template Engine can call the IGXTemplateData object as it needs data and return results as they are available, keeping the user waiting much less time for a response.

The Template Engine service of iPlanet Application Server automatically calls the MoveNext( ) method in the IGXTemplateData interface each time it needs a new row of data; for example, when it has completed one pass in a tile tag and is ready to start the next iteration of that tile. If you have implemented your own MoveNext( ) method, you can use that code to retrieve data as needed. This takes the place of calling RowAppend( ) repeatedly to populate the IGXTemplateData object all at once. After MoveNext( ) is called, Get( ) is called to retrieve the values in that row.

For example, the following code shows how the AppLogic code looks when you use RowAppend( ):

// Populate the in-memory template data. The number

// of calls to RowAppend() is unlimited. Meanwhile,

// the user is waiting for an unknown length of time

// until the full template data set is populated.

//

GXTemplateDataBasic *td;

td = new GXTemplateDataBasic("offices");

td->RowAppend("office=New York;revenue=150");

td->RowAppend("office=Hong Kong;revenue=130");

// ... add more records here.

// Pass the finished data set to EvalTemplate().

HRESULT hr;

hr = EvalTemplate("salesReportByOffice.html",

   (IGXTemplateData *) td, NULL, NULL, NULL);

td->Release();

return hr;

Now suppose you create your own implementation of the IGXTemplateData interface or subclass from the GXTemplateDataBasic class. The following code is in the header file:

class MyTemplateDataBasic : public GXTemplateDataBasic

{

public:

   MyTemplateDataBasic(LPSTR group) :

      GXTemplateDataBasic(group)

   {

      // Prepare the retrieval of the offices records here.

      // We don't have to get all the data yet, just

      // the first record data.

   }

   STDMETHOD(IsEmpty) (

      LPSTR group,

      BOOL *empty

   );

   STDMETHOD(MoveNext) (

      LPSTR group

   );

   STDMETHOD(GetValue) (

      LPSTR szExpr,

      IGXBuffer **ppBuff

   );

};

The following code is in the source file:

STDMETHODIMP

MyTemplateDataBasic::GetValue(LPSTR field,

   IGXBuffer **ppBuff)

{

   if (strcmp(field, "offices.office") == 0)

   {

      IGXBuffer *office;

      // ... retrieve current office field value here.

      *ppBuff = office;

      return NOERROR;

   }

   if (strcmp(field, "offices.revenue") == 0)

   {

      IGXBuffer *revenue;

      // ... retrieve current revenue field value here.

      *ppBuff = revenue;

      return NOERROR;

   }

   return GXTemplateDataBasic::GetValue(field, ppBuff);

}

STDMETHODIMP

MyTemplateDataBasic::IsEmpty(LPSTR group, BOOL *empty)

{

   if (strcmp(group, "offices") == 0)

   {

      boolean isOfficeRecordSetEmpty;

      // ... determine if the data set is empty.

      *empty = isOfficeRecordSetEmpty;

      return NOERROR;

   }

   return GXTemplateDataBasic::IsEmpty(group, empty);

}

STDMETHODIMP

MyTemplateDataBasic::MoveNext(LPSTR group)

{

   if (strcmp(group, "offices") == 0)

   {

      HRESULT noMoreRecords;

      // Move to next record in offices data set here.

      // This is where we can dynamically compute

      // the next record.

      //

      // Return NOERROR (0) if next record is available.

      // Return non-zero if no more records.

      return noMoreRecords;

   }

   return GXTemplateDataBasic::MoveNext(group);

}

The following code shows how the AppLogic looks when you let the Template Engine retrieve the data through MoveNext( ):

// Use our own GXTemplateDataBasic subclass, which is

// smart enough to dynamically retrieve office records

// when called back by the template engine. This allows

// data to be streamed back to the user as it becomes

// available, instead of waiting for the entire

// data set to be created first in memory.

//

MyTemplateDataBasic *td;

td = new MyTemplateDataBasic("offices");

// MyTemplateDataBasic retrieves office records

// as necessary, so we do not prepopulate it here.

// Pass the MyTemplateDataBasic object to EvalTemplate().

HRESULT hr;

hr = EvalTemplate("salesReportByOffice.html",

   (IGXTemplateData *) td, NULL, NULL, NULL);

td->Release();

return hr;



Using Conditionals in an HTML Template



You can vary the output from a template depending on specified conditions. For example, in order to have different content depending on the user's browser, you could use the following tags in your template:

text for all browsers.

text for all browsers.

%gx type=cell id=netscapeOnly%

   text for netscape browser only.

   text for netscape browser only.

%/gx%

text for all browsers.

%gx type=cell id=microsoftOnly%

   text for internet explorer browser only.

   <blink>you're using

    MS!</blink>

   text for internet explorer browser only.

%/gx%

text for all browsers.

text for all browsers.

In your AppLogic, set up a template map with values for the keys used in your conditional tag. You might want to put this code is in your application base class or a helper function.

BOOL isNetscapeBrowser;

BOOL isMicrosoftBrowser;

// ... Compute browser type here, not shown ...

// Populate template map.

//

GXTemplateMapBasic *m;

m = new GXTemplateMapBasic();

IGXBuffer *buff;

buff = GXCreateBufferFromString("");

m->Put("netscapeOnly", isNetscapeBrowser ? NULL : buff);

m->Put("microsoftOnly", isMicrosoftBrowser ? NULL : buff);

buff->Release();

// ... Use map here, such as with EvalTemplate, not shown ...

m->Release();

Provide values for the boolean variables by consulting the input parameters in your AppLogic's input ValList.



Example HTML Template



Several example applications are shipped with iPlanet Application Server software, and the HTML templates used by these applications are available for you to view. The following example presents one of those templates with explanatory comments:

This example application displays a report on states in a given geographic region. For each state in the region, an illustration of the state flag and population figures for each county are displayed.


HTML Template for Region & States Report
This template contains two nested tile tags, one to loop over the states and another to loop over the counties within each state. In this example, comments are provided before each GX markup tag. For information about the other tags in the template, refer to your HTML documentation.

<HTML>

<HEAD>

<TITLE>Region And States Report</TITLE>

</HEAD>

<BODY BACKGROUND="/GXApp/Demo/States/Backgrounds

   /logo30pctbkglight.gif">

<H3>Region And States Report</H3>

<TABLE BORDER=1>

   <TR>

      <TH COLSPAN=2>Counties by State</TH>

   </TR>

The following GX tag sets up a loop that repeats for each state. The type=tile attribute specifies that this is a looping marker. The id=STATES attribute specifies that the loop will repeat for each row of the result set from the STATES query. The MAX=50 attribute specifies that the loop can repeat no more than 50 times.

%gx type=tile id=STATES MAX=50%

   <TR>

      <TD ALIGN=CENTER>

The following GX tag displays the name of a state at the beginning of each tile repetition. The type=cell attribute specifies that the text block of this marker is replaced with a dynamic data value. The id=STATES.STATE attribute specifies the field in the result set that contains the dynamic value. The text block "Name of a state" is acting as a comment within the tag. When an AppLogic merges data with this template, the comment is replaced with dynamic data.

<b>%gx type=cell id=STATES.STATE%Name of a state%/gx%

</b>

</TD>

<TD ALIGN=RIGHT>

The following GX tag dynamically updates the filename of the illustration so that a different state flag is displayed for each state. The type=replace attribute specifies that a value in the text block is to be replaced dynamically. The id=STATES.STATE attribute specifies the field in the result set that contains the dynamic value. The value=ABBR attribute specifies the placeholder string that is to be replaced in the text block.

      %gx type=replace id=STATES.STATE value=ABBR%

         <IMG SRC="/GXApp/Demo/States/Images/ABBR.gif"

             width=100 height=60>

      %/gx%

   </TD>

</TR>

<TR ALIGN=RIGHT>

   <TD><b>County</b></TD>

   <TD><b>Population</b></TD>

</TR>

The following GX tag sets up a loop that will repeat for each county in a state. The type=tile attribute specifies that this is a looping marker. The id=DETAILS attribute specifies that the loop will repeat for each row in the result set from the DETAILS query. The MAX=100 attribute specifies that the loop can repeat no more than 100 times. This prevents the report from getting too long if a state has an unusually large number of counties.

%gx type=tile id=DETAILS MAX=100%

   <TR ALIGN=RIGHT>

The following GX tags display the name and population of each county in the state. The type=cell attribute specifies that the text block of each marker is to be replaced with a dynamic data value. The id=DETAILS.COUNTYNAM and id=DETAILS.POP attributes specify the fields in the result set that contain the dynamic values. The text block strings Name of a county and Its population are acting as comments within the cell tags.

            <TD>%gx type=cell id=DETAILS.COUNTYNAM%

               Name of a             county%/gx%</TD>

            <TD>%gx type=cell id=DETAILS.POP%

               Its population

            %/gx%</TD>

         </TR>

      %/gx%

   %/gx%

</TABLE>

</BODY>

</HTML>



Example GXML Template



The following GXML template formats an output data stream containing the best game statistics for a sports application:

<gx type=tile id="DETAIL" max=10>

<gx type=cell id="DETAIL.player">

</gx>

<gx type=cell id="DETAIL.games">

</gx>

<gx type=cell id="DETAIL.fstr">

</gx>

<gx type=cell id="DETAIL.mstr">

</gx>

</gx>


Previous     Contents     Index     DocHome     Next     
Copyright © 2000 Sun Microsystems, Inc. Some preexisting portions Copyright © 2000 Netscape Communications Corp. All rights reserved.

Last Updated April 26, 2000