The Parser Perl module is a package for parsing text. When used to make CGI applications, the programmer can specify the final HTML pages via MTML templates. An MTML template is simply ascii text that contains variables and callbacks. Representing pages using these templates allows for changes to be made to the pages without having to change any code.
To use Parser.pm in a Perl program, one should follow these steps:
new
method.
ParseText
or
ParseFile
functions, respectively.
The following sample code parses a file and prints the result to
STDOUT
:
|
Any text file can be put through the parser, but as a standard, specify a file holding text to be parsed with the parser with a .mtml extension.
These are the functions that make up the public interface.
AddMtmlCallback
AddMtmlCallbacks
SetVar
DeleteVar
DumpVars
GetValue
IsMtmlCallback
new
ParseText
ParseFile
Reset
VarExists
Descriptions:
AddMtmlCallback(callback_name,
package_name_or_reference)
Adds a callback to the parser's list of callbacks.
callback_name
package_name_or_reference
optional
main
package will be used.
Returns: 1 if callback was successfully added to table.
Usage:
$p->AddMtmlCallback("MyCallback", $self); |
AddMtmlCallbacks(callback_names,
package_name_or_reference)
Adds a list of callbacks to the parser's list of callbacks.
callback_names
package_name_or_reference
optional
main
package will be used.
Returns: 1 if callbacks were successfully added to table.
Usage:
$p->AddMtmlCallbacks(["Callback1", "Callback2"], $self); |
SetVar(var_name,
var_value)
Sets a variable to a value.
var_name
var_value
Returns: 1 if variable was successfully set.
Usage:
$p->SetVar("name", "Mike"); |
DeleteVar(var_name)
var_name
Returns: 1 if variable is successfully deleted from table.
Usage:
$p->DeleteVar("name"); |
DumpVars()
Used for debugging.
Returns: all name - value pairs in the variable table.
Usage:
$p->DumpVars(); |
GetValue(var_name)
var_name
Returns: value of variable, if found in table.
Usage:
$p->GetValue("name"); |
IsMtmlCallback(callback_name)
callback_name
Returns: 1 if callback exists in list.
new()
Returns: a new Parser object.
Usage:
$p = new MtmlParser(); |
ParseText(text_string)
text_string
Returns: parsed text.
Usage:
$text = "Hello my name is ${name}"; |
ParseFile(file_name)
file_name
Returns: parsed text.
Usage:
$p = new MtmlParser(); |
Reset()
Clears all of the variables from the variable table.
Returns: 1 if table is cleared.
Usage:
$p->Reset();
|
VarExists(var_name)
Returns: 1 if variable exists in table.
Usage:
|
Variables have the syntax: ${var_name}
, where
var_name is the name of the variable. In the template one
can set a variable as follows:
${var_name} = value
|
For example:
${foo}="This is a variable"
|
In this example, the value
for the variable is
enclosed in double quotes, but any delimiter may be used as long as
the closing delimiter matches the opening delimiter. The
value
may span more than one line. So, a
template such as:
|
could be parsed to expand its variables and produce the following:
<HTML> <HEAD> <TITLE>This is my page</TITLE> <HEAD> <BODY BGCOLOR=white> <H1>Hello Mike</H1> </BODY> </HTML> |
Note: to prevent a variable from being expanded, precede it with a backslash:
\${var_name} |
A callback executes a subroutine of the same name in the Perl code and is expanded to whatever text is returned. There are a number of callbacks that are built in to the main parser. Additionally, one can define new callbacks. This allows a piece of code to be embedded into a template without putting the actual code in the template. By making flexible callbacks whose output depends on the input parameters, it is posible to make highly reusable callbacks.
The syntax for a callback is:
@nameOfCallback(%`var1`,
`var2`, ... %) |
Notice that a callback can have a variable number of parameters passed to it. Each parameter is enclosed in back-ticks (`), not single quotes ('). These parameters will be passed to the subroutine that is invoked by the callback.
As with variables, a callback may be preceded with a backslash if it should not be expanded:
\@nameOfCallback(%`var1`, `var2` ... %) |
The pre-defined callbacks are:
And here are the details:
@LoadConfig(%`filename`%)
filename
A configuration file is a setup file that assigns values to variable names. One might contain text like:
name = "mike" |
Returns: 1 if successful.
Usage:
@LoadConfig(%`/home/me/setup/mysetup.setup`%) |
@Include(%`filename`%)
filename
Returns: 1 if successful.
Usage:
@Include(%`/home/me/templates/head.mtml`%) |
@IncludeHtml(%`URL`,
`flag`%)
URL
flag
optional
1
), indicates that the
URL's contents should be parsed.
Returns: true if successful.
Usage:
@IncludeHtml(%`http://www.splunge.com/cgi-bin/something.cgi`,
`1`%) |
@Exec(%`command`%)
command
#exec
, (using /bin/sh).
Returns: results of command execution.
Usage:
@Exec(%`ls -l | grep *.html`%) |
@If(%`condition`, `string1`,
`string2`%)
condition
eq
ne
<
>
==
!=
=~
!~
string1
condition
is
true.
string2
(optional)
condition
is
false.
Returns: string1
if
condition
is true.
otherwise returns string2
if given else
an empty string.
Usage:
>@If(%`${myVar} > 2`, `My variable is greater than 2!`%) |
@Unless(%`condition`,
`string`%)
condition
eq
ne
<
>
==
!=
=~
!~
string
condition
is
false.
Returns: string
if
condition
is false or an empty string is
condition
is true.
Usage:
@Unless(%`${name} eq "Mike"`, `You are not Mike!`%) |
@IfDef(%`var_name`,
`string1`, `string2`%)
var_name
string1
var_name
exists.
string2
(optional)
var_name
does not exist.
Returns: string1
if var_name
exists in the variable table.
otherwise returns string2
if given else
an empty string.
Usage:
@IfDef(%`name`, `Hello ${name}!`%) @IfDef(%`name`, `Hello ${name}!`, `who are you?`%) |
@IfNotDef(%`var_name`,
`string1`, `string2`%)
var_name
string1
var_name
does
not exist.
string2
(optional)
var_name
exists.
Returns: string1
if
var_name
does not exist in the variable table.
otherwise returns string2
if given else
an empty string.
Usage:
@IfNotDef(%`name`, `No name has been given`%) @IfNotDef(%`name`, `No name has been given`, `name is ${name}`%) |
@IfEmpty(%`var_name`,
`string1`, `string2`%)
var_name
string1
var_name
does
not exist or is an empty string.
string2
(optional)
var_name
is not an
empty string.
Returns: string1
if
var_name
is either an empty string or is not
defined in the variable table. Otherwise, returns string2
if given else an empty string.
Usage:
@IfEmpty(%`name`, `You must give me your name!`%) |
@IfNotEmpty(%`var_name`,
`string1`, `string2`%)
var_name
string1
var_name
is not an
empty string.
string2
(optional)
var_name
does
not exist or is an empty string.
Returns: string1
if
var_name
is defined in the variable table and is
not an empty string. Otherwise, returns string2
if
given else an empty string.
Usage:
@IfNotEmpty(%`name`, `Hello ${name}!`%) |
To define a new callback, the programmer needs to:
AddMtmlCallbacks
function in the new
constructor.
Consider the following example, in which a callback is created for the
GetRandomNumber
method.
The original method is:
|
The new method is:
|
The MTML text that uses this callback would be:
My random number is @GetRandomNumber(%`4`, `<font size=+2><B>`, `</b></font>`%) |
This might output HTML such as:
My random number is <font size=+2><B>3253</b></font> <P> |
Which looks like:
My random number is 3253 |
One of the best uses for this parser is for making multilevel templates for a group of HTML pages. The first step towards this end is determining which elements are common to all of the pages.
For example, consider a small web site with three sections:
The HTML for each of the three pages are:
Home.html: |
---|
|
Links.html: |
---|
|
About.html: |
---|
|
These three pages have some common elements. Specifically, the header, navigation, and footer HTML are similar, with minor differences. Most cases are more elaborate -- containing more in-between text -- but this is adequate for demonstration.
The most common things that would be extracted out for HTML page templates are, in fact, the header and the navigation. The text for each page is not exactly the same though; the title and navigation differ slightly. So, what would the appropriate templates look like? Like these:
Header.mtml: |
---|
|
Footer.mtml: |
---|
|
The previous two templates are then incorporated into the following templates:
Home.mtml: |
---|
|
Links.mtml: |
---|
|
About.mtml: |
---|
|
The files Home.mtml, Links.mtml, and About.mtml are the templates for
the three main pages. Each one sets two variables:
${title}
, and a switch variable
($NO_SHOW_ABOUT
, $NO_SHOW_LINKS
, or
$NO_SHOW_HOME
) that ensures that the current page does
not contain a 'hot' link to itself.
You may notice that each of the main templates has a very similiar structure. This leads to a second way of constructing the templates that actually makes them easier to maintain. Instead of having three pages that each include a header and a footer with text between the two includes, the overall structure can be represented in one general template with the text specific to each page put into a seperate template. So now our templates woule look like:
main.mtml: |
---|
|
Home.mtml: |
---|
|
Links.mtml: |
---|
|
About.mtml: |
---|
|
With this version you will need to fill in the ${title} and ${sub_template} variables as appropriate according to wich page you wish to see before you parse main.mtml. Thus to show the about page your code might look like:
$p = new MtmlParser(); |
Although it may seem a bit backwards at first, this kind of templating scheme makes it easy to maintain your templates.
As noted before, real templates would be more complicated. One can set
variables in the parser in of the program before the template is parsed
(either manually or through a setup file). Then the templates themselves
can load setup files to set variables (via the LoadConfig
callback).
As a general design principle, when using the Parser to make CGI applications, it is best to keep the templates as simple as possible and put the programming logic in the code. The point of a template is for it to be easily modified. Before the template is expanded, one's code should go through whatever programming logic is needed to populate the variables that will be embedded in the template. If there is a particular piece of logic that is being used repeatedly, that logic can be encapsulated into a new callback.