Web pages tend to use similar code and content over and over, starting with basic HTML document templates and page headers linking main sections of the site to advertisements and advanced dynamic menus. Page templates and code snippets can help a great deal to streamline inserting repetitive code, but overtime you may collect a large number of only slightly different templates making it cumbersome to maintain and use them. Code Wizards are also great tools, but often you may have to use a wizard designed by someone else that doesn't quite address your specific preferences and coding standards.
XSCL aims to provide a language independent method of maintaining a library of highly customizable and programmable snippets or scripts that can be quickly retrieved and tailored on the fly. Its ability to generate multiple pages or versions of content using a single code base, gives it the flexibility found in server-side scripting at the design time. Creating XSCL commands can be as simple as saving a piece of HTML code which requires no experience in script programming. The functionality of these commands can be gradually extended using scripts.
Example 1 -- dynamic templatesYou're creating a list of sales contacts in your company. Each entry will display the first name, phone extension and a picture, if available. With XSCL, you would first create a template for a single contact using a regular text/HTML editor. Then indicate which parts of the template will contain variable information, such as the first name and the phone extension. If this template is saved as "contact" you can use it within XSCL by typing following lines, one per contact. Note that Jane does not yet have a picture, but you can teach XSCL commands how to handle such empty fields.
Example 2 -- browser specific pagesTo get the best out of existing browsers, sometimes you may have to create two or more versions of the same page optimized to specific browsers. Trying to keep the content synchronized in multiple pages can be time consuming, but with XSCL you can create a single command that can generate two versions of the same page. Certain code inside XSCL commands can be blocked out or replaced using simple conditions.
Example 3 -- include multiple files into a single pageYou may have to include a file within another file to avoid having to repeatedly enter the same content. XSCL will not only make it easier to embed external files, but it'll also allow you to recursively include one file within another. |
Before we get into using XSCL, let's make sure that it's properly installed. You must have HTML-Kit Build 290 or higher to use this plugin.
table 2 4
As you've seen in examples above, "contact" and "table" are commands in XSCL. These commands are not built-into the XSCL plugin, but implemented by the user. These commands are stored in files with the *.xsc extension under the "HTML-Kit\Plugins\Config\XSCL" directory.
Before getting started, go to HTML-Kit's "Help | About" option and change to the "Program Details" tab. Write down the "Plugins Directory" path and append "\Config\XSCL" to it. For example, if the plugins directory is "HTML-Kit\Plugins" then "HTML-Kit\Plugins\Config\XSCL" is your XSCL directory.
Secondly, we need to add the *.xsc file extension to HTML-Kit because we'll be working on files with that extension. Go to "Edit | Preferences" from the main menu and change to the "File Types" tab. Select the "USER" file (don't uncheck it) and click "Add File Type." Enter "XSCL Files" without quotes and click OK. Enter "*.xsc" without quotes in the "File Type Extensions" field and click the "USER" file to make sure that the newly added file type was saved. Now click "Colorized file types" and enter ;xsc at the end of the "HTML, XML" field. Click OK to go back to the Preferences dialog and click OK again to close it.
We're now ready to create our first XSCL command, which we'll call the "hello" command. It'll simply insert the text "Hello, world!" into the editor.
First start HTML-Kit and open an absolutely empty document (make sure that it does not contain any text or tags). You can do this by holding the SHIFT key down while clicking the new file icon or selecting "File | New Document" menu item. Type "Hello, world!" without quotes and save the file as "hello.xsc" under the XSCL directory. Close the file.
To test your new command, open a new document and change to the XSCL tab on the Actions Bar. Type hello into the command field and press Enter. You should see the text "Hello, world!" inserted into the current document. Maybe it's a simple command, but now you know how to create XSCL commands! Of course you could have typed any other text or HTML tag into the hello.xsc file as well, but we'll get to more advanced XSCL commands later.
HKScript is the default programming language used in XSCL to create commands. But you can use virtually any scripting language to create commands, including Perl, PHP, Python, Java, Lisp, or any other language that you have an interpreter for. If you have Perl installed on your local machine, you can use perl.exe as the interpreter or php.exe if you have PHP. Simply include #!
followed by the executable file name of the interpreter on the very first line in the *.xsc file (similar to the #!
line in UNIX scripts).
XSCL command written in Perl
To test this code, save as a file with the *.xsc extension in the XSCL directory (perltest.xsc for example). Then type perltest testing
in the XSCL command field.
#!perl.exe
print "Hello, world!\n";
print "First parameter = $ARGV[0]";
XSCL command written in PHP
Note that the -q
argument is passed to php.exe
to exclude HTTP headers. Following sample assumes that the php.exe file is in the PATH. If not, include the full path (such as c:\php\php.exe)
#!php.exe -q
Hello, world!
First parameter = <?php echo $argv[1] ?>
The rest of this document assumes that HKScript is being used to program commands, since it's the only built-in language, however the same concepts should apply to any other language. Be sure to replace ParamStr[]
and ParamCount
variables with the equivalent variables in the language being used ($ARGV[]
in Perl and $argv[]
in PHP, for example. Also note that #if
, #endif
, #elif
and #else
lines are only supported in HKScript. Again you can use the equivalent commands in the language you're using.
Well, the arguments we're talking about here are the parameters passed to XSCL commands. For example, when you typed "hello" above, hello is the command and it did not take any parameters. But in the "contact" example, the contact command took either two or three parameters, depending on whether a picture was available or not. The table command took, at least in the above example, two parameters - the number of columns and rows.
Why are we talking about parameters? We'll be passing additional information to commands using parameters later on, so let's talk about parameters a bit more. Inside the *.xsc file, parameters will be represented using the following code (when using HKScript to write commands):
ParamStr[1]
The number 1 inside the square brackets indicate that the first parameter should be used. Given the following command line (command plus any optional parameters):
Contact Joe 5556 joe.jpg
ParamStr[1] is equal to "Joe" and ParamStr[2] is equal to "5556" and so on. The total number of parameters passed to a command is indicated in the ParamCount variable. In this case, it'll be set to 3 because the contact command took three parameters.
Anything separated by a space is a separate parameter, unless double quotes are used. For example, if the above command line was changed to:
Contact "Joe 5556" joe.jpg
then we have only two parameters, the first is "Joe 5556" and the second is "joe.jpg"
If you need to include a quote as part of a parameter, it must be escaped using the "\" character. For example:
Contact "Joe \"the joker\" 5556" joe.jpg
will become "Joe "the joker" 5556" which is the first parameter.
Ready to create your second command? Actually, let's extend the hello command.
Open the "hello.xsc" file from the XSCL directory. Replace the word "world" with the following:
<%=ParamStr[1]%>
so the full line should look like:
Hello, <%=ParamStr[1]%>!
Save the file. Open a new document and type the following into the XSCL command field:
hello joe
Note how it's inserting "Hello, joe!" or whatever the first parameter you've typed for the hello command. "hello mom" would insert "Hello, mom!"
Great! On to the next step...
That's right! If you enter the hello command without any parameters, now you'll get an error. This is because the hello.xsc file is expecting a parameter but it didn't find any. Here's the solution, change the following line in the "hello.xsc" file:
Hello, <%=ParamStr[1]%>!
to these three lines:
#if ParamCount > 0
Hello, <%=ParamStr[1]%>!
#endif
We've just programmed the hello command to print the text only if it finds at least one parameter (or technically speaking, more than 0 parameters). Remember that the ParamCount variable contains the number of parameters passed to the command. The "#if" line is used to indicate that the code below it, up to the "#endif" line, should be executed only if the number of parameters is greater than 0. Now when you type the hello command by itself, there won't be an error message, but if a parameter is specified it'll continue to work as before.
Before closing this section, let's add a few more lines of code:
#if ParamCount > 0
Hello, <%=ParamStr[1]%>!
#else
Hello, world!
#endif
See what happens when you type hello by itself. You'll get the text "Hello, world!" because of the "#else" line, which says that if the "#if" line above fails then use the code below the "#else" line.
If you have a header, a footer or other common piece of text that has to be included in multiple pages, you can place that text in a separate text file and easily include its content into *.xsc files:
<%!c:\banner.txt%>
<%!c:\footer.txt%>
Above code will include the text in the c:\banner.txt file and the c:\footer.txt file into the XSCL command file. Note that included files can also include files, for example the c:\footer.txt file could contain the following code to include the disclaimer.txt file in the current directory:
<%!disclaimer.txt%>
There are cases where you may have to optimize your pages to specific browsers. Rather than maintaining multiple copies of the same page, you can create a single XSCL command file that contain code for different browsers. Parts of that code can be included or excluded while running the XSCL command.
As a test drive, save the following code in a file named videopage.xsc in the XSCL directory:
Code common to all browsers
#if ParamStr[1] == "ns"
Netscape specific code
#endif
#if ParamStr[1] == "ie"
Explorer specific code
#endif
Now you can generate the Netscape specific page by running the command videopage ns
or the Explorer specific code can be invoked by running videopage ie
. The code shown above can also be written as follows to get the same results:
Code common to all browsers
<% if (ParamStr[1] == "ns") { %>Netscape specific code<% } %>
<% if (ParamStr[1] == "ie") { %>Explorer specific code<% } %>
As you see, the ==
operator (equal operator) is used to compare the value of ParamStr[1]
to either "ns" or "ie" If there's a match, the very next code block starting with {
(which is used to indicate the start of a block) and ending with }
will be used.
If you have several browser specific code blocks, it can be cumbersome having to type (ParamStr[1] == "..")
over and over. Here's one way to reduce the length of the comparison:
<% auto isNS = (ParamStr[1] == "ns"); %>
Code common to all browsers
<% if (isNS) { %>Netscape specific code<% } %>
<% if (!isNS) { %>Explorer specific code<% } %>
The first line compares the first parameter to "ns" and saves the result in a variable named isNS
. From that point on, you can use isNS
as the condition. The !
operator (not operator) can be used to check if it's not "ns" by using the code !isNS
as shown above.
<%
and %>
are used to mark the start and end of sections in XSCL command files that contain scripts. These scripts will get executed by XSCL before serving the final result of a command. The text and code outside of <% ... %>
blocks will be passed through without modification.
If #
is the first character in a line, rest of that line will be treated differently. For example, if #
is followed by a space, rest of that line will be ignored so you can use it to keep comments.
# this is a comment
If #
is immediately followed by if
, elif
, else
or endif
those lines will act as conditions within the XSCL command file.
#if 2 == 2
Of course 2 is equal to 2, so you'll see this line.
#else
But you'll never see this line in the output.
#endif
You've already seen the table
command in action. It can generate the HTML code for a table containing the user specified number of columns and rows. Following command will generate a table with 2 columns and 4 rows:
table 2 4
Following code in the table.xsc file does all the work:
<% auto col = 0, row = 0; %>
#if 2 == ParamCount
<table>
<% for( row=1; row<=ParamInt[2]; row++ ) { %>
<tr>
<% for( col=1; col<=ParamInt[1]; col++ ) { %>
<td></td>
<% } %>
</tr>
<% } %>
</table>
#endif
The very first line simply reserves two variables for storing numbers named col
and row
. These variables are used by the two for
commands to create the given number of columns and rows. The second line should be fairly familiar by now, we're simply checking whether the table command received two parameters, the number of columns followed by the number of rows.
Because the 3rd line did not start with a #
character and it's not inside a <% %>
block, it does not have a special meaning, so it'll simply get passed through to the final output.
Since the two for
commands does most of the work, let's examine them closer:
for( row=1; row<=ParamInt[2]; row++ )
It's saying that the row
variable, defined at the top as a variable capable of holding numbers, will start at 1 (row=1
), and increment one at a time (row++
) until it exceeds the value of ParamInt[2]
(row <= ParamInt[2]
). ParamInt[2]
is the same as ParamStr[2]
except ParamInt[2]
is a number instead of a string of characters (or something that's holding arbitrary text). If you remove the ParamInt[2]
from the for
command, it could be written as follows to count from 1 to 10:
for( row=1; row <= 10; row++ )
The second for
command is the same, except it's dealing with the number of columns instead of rows:
for( col=1; col<=ParamInt[1]; col++ )
So what's happening here? The first for
command is going through a loop until it generates the specified number of rows, while the second for loop is generating the specified number of table cells.
Following code can be used to generate a given number of paragraph tags. To test, save the code in a file named paras.xsc in the XSCL directory and run the command paras 5
to generate 5 paragraphs.
#if 1 == ParamCount
<%
auto paragraphs=0;
for( paragraphs=1; paragraphs <= ParamInt[1]; paragraphs++ )
{
%>
<p></p>
<%
}
%>
#endif
Can XSCL really save you time? Let's look at some sample XSCL commands that you could create and use to speedup day-to-day HTML coding.
Beat this table!Save the following code as fasttable.xsc
#if ParamCount > 0
<table border="1">
<%
auto cells=0;
for( cells=1; cells <= ParamCount; cells++)
{
%><tr><td><%=ParamStr[cells]%></td></tr>
<%
}
%></table>
#endif
Now simply type fasttable
followed by the text you want each cell in the table to contain, and you won't have to enter a single HTML tag. For example, the following line will create a table containing three rows with the specified text:
fasttable "write once" "and" "reuse many times!"
You can modify the above code to create commands to quickly enter multiple paragraphs, images, email addresses, etc. A fastemaillist.xsc command may look like:
#if ParamCount > 0
Contacts:
<%
auto address_count=0;
for( address_count=1; address_count <= ParamCount; address_count++)
{
%><a href="mailto:<%=ParamStr[address_count]%>"><%=ParamStr[address_count]%></a>
<%
}
%>
#endif
n = chartoint("A"); // = 65
var a1 = new array("a","b","c");
del(a1, 1, 1);
// a1 = {"a","c"}
del(a1);
// a1 = {}
str = floattostr(45.31);
s = inttochar(65); // = "A"
str = inttostr(123);
str = join(",", ary);
n = length("text"); // = 4
pop(ary);
push(array1, str);
array2 = sort( array1 );
str = sprintf("%s %d", "I'm", 16); // = "I'm 16"
str = strlwr("UPPER"); // = "upper"
f = strtofloat("99.4");
n = strtoint("78");
str = strupr("lower"); // = "LOWER"
array2 = subarray(array1, 5, 2);
str = substr("hands", 1, 3); // = "and"
var array1 = new array("one", "two", 3, "three", "3", "two");
var array2 = new array();
array2 = unique(array1);
// array2 = {"one", "two", "3", "three"}
var s1 = "abc1bbc32", s2 = "";
s2 = uniques(s1);
// s2 = "abc132"
var array1 = new array("one", "two", 3, "three", "3", "two");
var array2 = new array();
array2 = rfilter("t", array1);
// array2 = {"two", "three", "two"}
array1 = rgather("(\\d)", "4 5 6"); // = array1 = {"4","5","6"}
str = rgathers("(\\d)", "4 5 6");
if( rmatch( "\\d", "55 Mhz") ) { /* found a number */ }
n = rpos("a", "abca"); // n = 0
n = rpos("a\\Z", "abca"); // n = 3
str = rreplace("\\d", "*", "55 Mhz", "g"); // = "** Mhz"
array1 = rsplit( "\\/", "2/10/2001"); // = {"2", "10", "2001"}
array2 = rsplit( "c", "abcdccef"); // = {"ab", "d", "", "", "ef"}
array2 = rsplit( "c", "abcdccef", "-"); // = {"ab", "d", "ef"}
str = strrepl("ABCA", "A", "a"); // = "aBCA"
str = strreplall("ABCA", "A", "a"); // = "aBCa"
if( faccess("myfile.txt", 0) ) { /* myfile.txt exists */ }
fcopy( "file.txt", "newfile.txt" );
while(NULL != (character = fgetc(file_handle))) { /* use "character" */ }
str = fgets(file_handle);
while(NULL != (str = fgets(file_handle))) { /* use "str" */ }
var f = 0, l = 0;
f = fopen("file.txt", "r");
if(f){ l = flength(f); fclose(f); }
// l = size of the file in bytes
array1 = flist("*.jpg");
array1 = flist("*.*", 0x00000010); // get a list of directories
fmove( "file.txt", "new_name.txt" );
var f = 0;
f = fopen("myfile.txt", "r");
if( f ) { /* read the file and close it */ fclose(f); }
fputc(65, file_handle);
fputs(str, file_handle);
fremove("obsolete_file.txt");
aFileInfo = fstat("index.html");
// aFileInfo[7] = file size in bytes
str = ftempname("test", ".htm");
str = hsprintf("%s > %d", "I'm", 16); // = "I'm > 16"
str = htext("< not html >"); // = "< not html >"
str = hunformat("<^Tbr^N ^Aclear^N=^Qall^Q>", 0); // = <br clear="all">
str = ugets("http://localhost");
usave("http://localhost", "file.txt");
db_close(dbHandle);
db_end(dbResult);
str = db_error(dbHandle);
dbResult = db_exec(dbHandle, "SELECT * from MyTable");
if( db_fetch(dbHandle) ) { /* successfully loaded a table row */ }
str = db_field(dbResult, "ProductName");
n = db_fieldcount(dbResult);
n = db_fieldid(dbResult, "ProductName");
str = db_fieldname(dbResult, 3);
str = db_info(dbHandle);
dbHandle = db_open("dsn=MY_DATA_SOURCE");
n = abs(-1); // = 1
Alert("message", "title");
h = AppHandle();
str2 = copy(str1);
die("out of memory");
dllruni("user32.dll", "MessageBeep", 1);
if( equal(str1, str2) ) { }
exec("notepad.exe", 1);
exec("dir", 1, 1, aStdOut);
exec("mem.exe", 1, 1, aStdOut, aStdErr);
ExecuteAndWait("notepad.exe", "myfile.txt", "c:\\myfiles", 1);
exit(0);
str = getenv("PATH");
str = gettime("m/d/yyyy") // = "2/9/2001"
MessageBox("message", "title", 1);
// Yes/No prompt
if( 6 == MessageBox( "Exit?", "Confirm", 4 ) )
{ /* Yes */ }
putenv("MY_PATH", "c:\\temp");
if( "string" == typeid(str) ) { /* this is a string variable */ }
if( use("MyHKSLib") ) { MyHKSLib.newfunc(); }
if( use("MyHKSLib.dll", "XYZ") ) { XYZ.newfunc(); }
uudecodef(str, "new.gif");
str = uuencodef("picture.gif");
WinExec("notepad.exe", 1);
Looking for more samples and ready-to-use commands? Checkout the XSCL Gallery.
Please use the htmlkit.plugins newsgroup to post comments, corrections and questions related to this article.
Copyright (C) Jan-2002, Chami.com. All Rights Reserved.