The SteelBlue language is an augmentation of HTML with new tags and flags suited for database, variable, and form manipulation. All HTML tags are legal in SteelBlue. In addition, SteelBlue gives you the ability to say:
<HTML>
<BODY>
<SQL SQL="select FIRST_NAME, LAST_NAME
from PERSON
where PERSON_ID = '22'"
NAME="person">
<H2>
Hello
<REPLACE VALUE="$person{FIRST_NAME} $person{LAST_NAME}">
</H2>
</BODY>
</HTML>
The SQL statement accesses the database
and returns the first row of data in the namespace "person". The REPLACE tag takes the VALUE string,
substitutes variables with their values, and prints the result into
the HTML stream.
The example above demonstrates the power of SteelBlue. Not only does SteelBlue allow easy database access, it provides complex form checking, automatic error recovery, and built-in security.
SteelBlue was designed to encompass all aspects of form manipulation in a single script:
<HTML>
<BODY>
<SHOWERRORS>
<CENTER>
<H2>Personal Information</H2>
<SBFORM NAME="myform" SCREEN="welcome">
Your name: <INPUT NAME="name" REQUIRED>
<br>
Your e-mail: <INPUT NAME="email" datatype="email"
REQUIRED>
<br>
<INPUT NAME="spam_check" VALUE="Y" TYPE="CHECKBOX">
Check if you don't like Spam®
<hr>
<INPUT NAME="submit" type="submit">
<INPUT NAME="cancel" type="button"
VALUE="Cancel"
onClick="window.history.go(-1)">
</SBFORM>
</CENTER>
</BODY>
</HTML>
<CHECK>
<SBFORM NAME="myform">
<!-- Make sure they like Spam -->
<IF BOOL="$this{spam_check} eq 'Y'">
<ERROR text="You must like Spam® to continue">
</IF>
</SBFORM>
</CHECK>
<ACTION>
<SBFORM NAME="myform">
<!-- Copy form data to preferences -->
<COPY SOURCE="this" DESTINATION="preferences">
<!-- Save preferences to the Swap for later use -->
<SAVE NAMESPACE="preferences">
</SBFORM>
</ACTION>
Let's explore the Spam® example in detail.
SteelBlue tags support links and form submissions to pages both inside and outside a SteelBlue application. A form made with an SBFORM tag indicates that the destination of the form submission is another SteelBlue page. Similarly, links to other SteelBlue pages are made with an SBREF tag. In the Spam® example, the SCREEN tag specifies that if the form is submitted and the CHECK and ACTION sections complete without error, then the HTML section of SteelBlue file "welcome" will be executed.
SteelBlue can automatically check the datatypes of the input elements on both the client and server side by adding a DATATYPE flag. (Please see INPUT tag for details on type checking). If you put a REQUIRED tag in an input element, that element becomes required, and the user will not be able to continue without filling it in. Server-side checking of datatypes and required elements is automatic; you can configure SteelBlue to check datatypes and required elements on the client side using JavaScript functions (included in the file "CheckUtils.js"). In the Spam® example, the "email" field must conform to the e-mail format. In addition, both "email" and "name" must be entered by the user in order to continue.
There are many more tags available in the HTML section,
including tags for database access, file manipulation, and e-mail
transmission. For more information, please see the SteelBlue Tag Reference.
It is important to implement error checking on a form only if that
particular form is submitted. For example, there may be multiple
forms on a single page or the user may be able to leave a page without
submitting a form (say by clicking on a link). In these cases, an SBFORM container can conditionally execute
code if its associated form in the HTML section was submitted. In the
Spam® example, the SBFORM container
surrounds error checking code for the form named "myform".
The data submitted by a form is placed in an associative array with the namespace
"this". In the Spam® example, an IF
statement confirms that the user has not checked "Check if you don't
like Spam$®." The contents of the IF
container executes if the BOOL flag (when evaluated with the Eval language) is true.
Errors can be manually thrown using the
ERROR tag. If an error is thrown, the rest of the CHECK section
executes, the ACTION section is skipped, and the HTML section is
redisplayed. In the Spam® example, an error is thrown if the user
checks the CHECKBOX stating that they do not like Spam®.
There are many more tags available in the CHECK section,
including tags for database access, file manipulation, and e-mail
transmission. For more information, please see the SteelBlue Tag Reference.
As in the CHECK section, the data submitted by a form is placed in the
associative array "this". In the
Spam® example, The action section copies the "this" namespace into
a "preference" namespace with the COPY
tag. It then stores the "preference" namespace into a server-side
repository of data called the Swap for later use
in other pages. Since they are surrounded with an SBFORM container, these tags are executed
if the appropriate form was submitted in the HTML section.
If the ACTION section is successful, the HTML section of the destination
page (determined by the SCREEN tag of an SBFORM,
SBREF, FRAME, or
REDIRECT tag) executes. If errors occur
in the ACTION section, the originating HTML section is redisplayed with
user entires restored.
There are many more tags available in the ACTION section,
including tags for database access, file manipulation, and e-mail
transmission. For more information, please see the SteelBlue Tag Reference.
The CHECK Section
The purpose of the CHECK section is to test the user's data
for validity before proceeding. If there is an error,
the rest of the CHECK section executes (in order to collect
all possible errors), the ACTION section is skipped, and the HTML
section is redisplayed with any user entries restored.
The ACTION Section
The purpose of the ACTION section is to implement database, e-mail,
and file transactions based on valid user data. The ACTION
section executes only after the user's data has been checked with the
CHECK section.
Order of Section Execution
Web interaction occurs between the HTML and CHECK sections of a single
page. In fact, if a form submission is successful, the CHECK and
ACTION sections of the originating page and the HTML section of the
destination page are executed one after another. For experienced CGI
programmers, it seem odd at first to have the code for the
manipulation of a form in the same file as the form generation, but we
have found that it makes Web applications easier to create,
understand, and maintain.
Variables
Since the fundamental use of SteelBlue tags is to manipulate data
(either database data or form data), variables are an important aspect
of SteelBlue. In SteelBlue tags, all variables contain strings. The
Eval language uses type conversion to generate
integers, real numbers, and Booleans from strings, but from
SteelBlue's vantage point, everything is a string.
There are two types of variables in SteelBlue whose syntax are taken from Perl:
will print out "Hello Mary Kathrine!"<ASSIGN NAME="$a" VALUE="Mary Kathrine"> <REPLACE VALUE="Hello $a!">
<ASSIGN NAME="$person{FIRST_NAME}" VALUE="Mary">
<REPLACE VALUE="The first name is $person{FIRST_NAME}">
The index can either be a string constant, or any Eval expression that returns a string (for
example $person{FIRST_NAME}, $person{"First Name"},
$person{$index}, or even $person{$index{HI} . "_NAME"}).
The variable name is called the namespace of the associative array. Tags like SQL or LOOP operate on whole namespaces:
<LOOP SQL="select username
from AuthUsers
order by username"
NAME="user">
<REPLACE value="$user{username}">
<br>
</LOOP>
The LOOP container repeats its contents
for each row of data returned from the database. The row of data is
stored in the namespace "person" (determined by the NAME flag). The
REPLACE tag prints the retrieved name
in the HTML stream.
Whole namespaces can be stored into and retrieved from the Swap (a server-side repository of client data) using the LOAD and SAVE commands.
<ACCUMULATE NAME="color_list"
SPLIT=","
VALUE="red,blue,green,pink">
<!-- $color_list{0}="red",
$color_list{1}="blue",
$color_list{2}="green",
$color_list{3}="pink", and
$color_list{LENGTH}="4" -->
<LOOP NAME="color" array="color_list">
<REPLACE VALUE="$color{value}">
<br>
<LOOP>
prints "red", "blue", "green", and "pink" separated by line breaks.
Arrays can be stored into and retrieved from the Swap using the LOAD and SAVE commands.
| Special Variables | |
|---|---|
| Variable or namespace | Purpose |
| $USER{username} | The user's username |
| $USER{institution} | The user's institution |
| $USER{ticket} | The user's session ID |
| $USER{this_page} | The page being executed |
| $USER{last_page} | The page previously executed |
| $installed{handler} | Function to call in case of an SQL error (see Database Error Handlers) |
| $this | Namespace into which form data is placed (for CHECK and ACTION sections) |
| $last | Namespace into which form data is placed (for following HTML section) |
Any global variable set in the CHECK section is available in the following ACTION and HTML sections. Any global variable set in the ACTION section is available in the following HTML section. Therefore, global variables can be used to pass messages to the next executing page (instead of using the Swap which causes database access). This means that an HTML section has two copies of the previous page's form data: the $this namespace (which could have been modified in the previous CHECK and ACTION sections) and the $last namespace (which has a clean copy of the form data).
For guest users, Swap data is deleted when the guest's ticket expires. For non-guest users, Swap data will last until the data is cleared with a CLEAR tag and can be used within and between sessions.
A flag can occur without a value, in which case its value is assumed to be the empty string (""). Values without spaces do not need surrounding quotes. If quotes are required to surround the values, either back single quotes (') or back double quotes (") can be used.<COMMAND FLAG1="VALUE1" FLAG2="VALUE2" ...>
If a tag is also a container, it terminates with an end tag of the form:
However, unlike most HTML interpreters, SteelBlue does not allow improperly nested containers:</COMMAND>
<B> <FONT COLOR=RED> </B><!--Illegal since B was opened before the FONT tag--> </FONT>
The EMAIL tag copies the newline characters directly into the e-mail set to the user $email. Flag contents also support the following escape sequences:<EMAIL VALUE="$email" SUBJECT="hi" MESSAGE=" Dear Customer: Thank you for using SteelBlue. We hope that you find it as easy to use as we do, and we greatly look forward to receiving any suggestions and improvements you have. ">
| Character Escape Sequences | |
|---|---|
| Escape Sequence | Output Character |
| \t | Tab |
| \n | New Line |
| \r | Carriage Return |
| \0 | NULL Character |
| \\ | Backslash |
| \' | Single Quote |
| \" | Double Quotes |
If the backslash precedes any character other than the ones above, SteelBlue ignores the backslash.
Use escape sequences to incorporate quotes in a string surrounded by the same type of quote:
<REPLACE VALUE="She said, \"$quote\"">
Some flags are parsed by a Perl-like language called the Eval language (see Eval Interpretation below). As the Eval language also uses escape sequences, you must take care to properly escape special charaters:
<!-- In the following, the backslash needs to be
escaped once for SteelBlue and once for Eval,
leading to four backslashes -->
<IF BOOL="$char eq '\\\\'">
The character is a backslash
</IF>
In these cases, it is much easier to use an EVAL container:
<EVAL>
if ($char eq '\\'){
print("The character is a backslash");
}
<EVAL>
<ASSIGN NAME="$id" VALUE="22">
<SQL SQL="select FIRST_NAME
from Person
where PERSON_ID = '$id'"
NAME="person">
<REPLACE VALUE="The first name is $person{FIRST_NAME}">
In the SQL tag, "22" replaces "$id" before the
select command execution, and in the REPLACE
tag the results of the select command replaces "$person{FIRST_NAME}".
To avoid SQL errors caused by quotes, SQL tags escape the quotes for the $this or $last namespaces before execution. (Please see the section on data sources for more information.) For example:
<ASSIGN NAME="$this{Name}" VALUE="Robert O'Donald">
<SQL SQL="insert into Person (Name)
values ('$this{Name}')">
Because the variable $this{NAME} is in the $this namespace, the quote
in "O'Donald" is properly escaped before the SQL statement is executed.
In the SteelBlue Tag Reference, flags that appear in RED have variable substitution.
<IF BOOL="dtTime($this{START_DATE}) == dtTime('08/19/1946')">
You were born the same day Bill Clinton was!
</IF>
In the SteelBlue Tag Reference, flags that appear in GREEN have Eval interpretation. The ASSIGN and REPLACE tags can have their VALUE flags passed through Eval interpretation if the EVAL flag is set. For example:
will print the "1 + 1 = 2".<assign name="$i" value="1"> <replace value="$i + 1 = "> <replace value="$i + 1" EVAL>
Large sections of Eval code can be placed in the EVAL tag. For example, the following prints the prime numbers between 1 and 100 using the Sieve of Eratoshenes:
<CLEAR NAMESPACE="composite">
<EVAL>
$max_num = 100;
for($i=2; $i<$max_num; $i=$i+1){
if (! $composite{$i}){
print($i.", ");
for($j=2*$i; $j<$max_num; $j=$j+$i){
$composite{$j} = 1;
}
}
}
</EVAL>
<script>
var i = 0;
if (i < 1) { // Illegal: "<" not allowed
// outside of a tag!!!
alert("i is less than 1")
}
</script>
The easiest fix is to rewrite the code using ">":
<script>
var i = 0;
if (1 > i) { // Much better
alert("i is less than 1")
}
</script>
Another possibility is to include the code in a comment (although then
you will not be able to incorporate SteelBlue tags into the
JavaScript):
<script>
// <!--
var i = 0;
if (i < 1) { // Legal since "<" is now
// in a comment
alert("i is less than 1")
}
// -->
</script>
Provides a single column of data from the given array.
Provides multiple columns of data (one column for each array). If one array is longer than another, the shorter array is padded with empty string entries.
Provides a single column of data of numbers starting from the min_num and incrementing by step_num to the max_num. STEP defaults to 1.
Provides multiple columns of data. The number of columns is determined by the number of columns given in the select statement. SteelBlue escapes quotes during string substitution for the $this and $last namespaces.
Provides a single value of data.
Provides a single column of data. The number of rows is determined by the number of value entries.
The SQL flag has special string substitution to avoid SQL errors caused by unescaped quotes. Variables from the $this or $last usually come directly from the user and are therefore escaped according to the rules from the database used (see escapeQuote). Variables from other namespaces are substituted directly without modification.
The tags ACCUMULATE and EMAIL operate on a single column, which is the first (leftmost) column for any data source. The tags SQL, SBSELECT, and LOOP operate on multiple columns, in which case the column names may be required to manipulate data.
For all data sources, the column names "0", "1", ... are used for the first, second, ... columns respectively. The number of columns is placed in the column name "LENGTH". This allows namespaces that are the result of LOOP and SQL tags to be used as arrays. For example, if the AuthUsers table contained:
| username | institution | password |
|---|---|---|
| admin | 0 | foy6TgL.HboTE |
| john | 0 | foKntnEF3KSXA |
| mary | 0 | bab.5ZXQdbvEo |
The following code creates a dynamically sized table whose width matches the number of columns returned in the table AuthUsers:
<TABLE border = 1>
<LOOP SQL="select * from AuthUsers" name="user">
<TR>
<LOOP NAME="column" array="user">
<td><replace value="$column{0}"></td>
</LOOP>
</TR>
</LOOP>
</TABLE>
The above code would output:
| admin | 0 | foy6TgL.HboTE |
| john | 0 | foKntnEF3KSXA |
| mary | 0 | bab.5ZXQdbvEo |
Note that the inner loop uses "user" as an array that generates a single column of data out of the row of data selected in the outer loop.
The first column of data of a data source is given the column name "value". For SQL statements, the columns are also given the names returned by the database. The following example does an SQL query and prints out all of the column names and values set by the query:
<SQL SQL="select * from AuthUsers" name="user">
<EVAL>
for($key = nextkey($user,"");
length($key) > 0;
$key = nextkey($user,$key)){
print("$user{".$key."} = ".$user{$key}."<br>");
}
</EVAL>
On a mySQL database, this results in the columns "0", "1", "2",
"LENGTH", "insert", "password", "username", and "value". For ORACLE,
the column names returned by the database are in upper case.
When a function is executed, a new environment is created in which you can declare local variables with the DECLARE command (you can also be declare local variables using the my Eval function). Please see the Eval Functions section for more information, an example of a recursive function, and how to define a function using the function Eval keyword.
<DEFFUN FUNC="inputAddress($prefix)">
<table>
<tr>
<td align=right>Address 1:</td>
<assign name="$inputname" value="$prefix . 'ADDR1'" EVAL>
<td><input type="text" name="$inputname" size=40></td>
</tr>
<tr>
<td align=right>Address 2:</td>
<assign name="$inputname" value="$prefix . 'ADDR2'" EVAL>
<td><input type="text" name="$inputname" size=40></td>
</tr>
<tr>
<td align=right>City:</td>
<td>
<assign name="$inputname" value="$prefix . 'CITY'" EVAL>
<input type="text" name="$inputname" size=20>
State:
<assign name="$inputname" value="$prefix . 'STATE'" EVAL>
<input type="text" name="$inputname" size=2>
Zip:
<assign name="$inputname" value="$prefix . 'STATE'" EVAL>
<input type="text" name="$inputname" size=5>
</td>
</tr>
</table>
</DEFFUN>
<sbform name="test" screen="welcome.sb">
<b>Home Address:</b><br>
<EVAL>inputAddress("HOME_");</EVAL>
<P>
<b>Work Address:</b><br>
<EVAL>inputAddress("WORK_");</EVAL>
</sbform>
This results in a form that looks like:
<DEFFUN FUNC="$res = dateDiff($a,$b)">
<assign name="$res" value="dtEpoc($a) - dtEpoc($b)" EVAL>
</DEFFUN>
<replace value="dateDiff('1/1/2001','1/1/2000');" EVAL>
This prints the value "366". Please see the
Eval Functions section to
see this function defined in Eval using the function Eval keyword.
The error handler function should have three arguments:
The return value of the error handler will determine what happens after its execution. If the error handler returns "0", SteelBlue interpretation will terminate as soon as the error handling function completes. Otherwise, SteelBlue interpretation will continue just after the SQL statement.
The following is an example of defining and using a database error handler:
<HTML>
<BODY>
<!-- Create a function to be an error handler -->
<deffun func="$res = ERROR_HANDLER($text,$code,$type)">
<if bool="$type == 2"><!-- DB Error Object -->
<!-- Print out the message -->
<P>
<replace value="DB Error $code: $text">
<else><!-- Unknown Error Object -->
<replace value="Unknown error type">
<!-- Do not continue after the error -->
<assign name="$res" value="0">
</if>
</deffun>
<!-- Install the handler -->
<assign name="$installed{handler}" value="ERROR_HANDLER">
<!-- Try an SQL statement that will fail -->
<sql sql="select asdf from fdsa" name="test">
<P>
Hey, we survived a bad SQL statement!
</BODY>
</HTML>
For mySQL, this created the following output:
DB Error : Error while processing SQL: select asdf from fdsa Hey, we survived a bad SQL statement!