[ZDP] [ZDP]DTML-Var sub tree
Dody Gunawinata
dody_g@eles.com
Tue, 19 Oct 1999 09:58:58 +1000
This is a multi-part message in MIME format.
--------------A5DCA96ACA6DA20D7E7FBA37
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Hi all,
This is the DTML-var tree content. It's partially complete as they are a
lot of aspect of var tag that needs to be explained.
I'll call this draft 1 :)
dody
--------------A5DCA96ACA6DA20D7E7FBA37
Content-Type: text/plain; charset=us-ascii;
name="Var.txt"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="Var.txt"
var tag is the simplest tag of DTML tags, the most powerful, and the mostly used.
The first attribute of *var *tag is *name* attribute. The purpose of this attribute is to display any data in the variable as a text. Remember this, it's very important.
*name* attribute does nothing else, it only displays a value in a variable. You have a variable with a value in it, to display it, use the *name* attribute of *var* tag.
This is how *var* tag with *name* attribute. Remember that the syntax below is the new DTML style syntax (after Zope 2).
<dtml-var name="variable">
Replace variable with any type of variable. The double quotes ("") is not compulsory with the *name* attributes, but it is a good practice to use it.
However there is another way of expressing *var* tag with *name* variable. A shortcut.
<dtml-var variable>
Replace variable with any type of variable. Notice that there is no double quotes enclosing the variable. It is *important* to remember this, because
if you enclose the variable in doublequotes, it would mean something else (more on this later).
Again, the *name*attributes display a value in a variable as a text. So if you try below example, it won't work.
<dtml-var name="Display this text">
You need a variable. So, how do you set up a variable ? Well, later. For the time being, let's just you variables that are already there. That are already provided by Zope.
Below is a list of the read-only CGI variables provided by Zope (from DC's Zope DTML Sser's Guide). Remember that variables in Zope is *case sensitive*.
SERVER_SOFTWARE The name and version of the information server software answering the request. Format : name/version.
SERVER_NAME The server's host name, DNS aliast or IP address as it would appear in self-referencing URLs.
GATEWAY_INTERFACE The revision of the CGI specification to which this server complies. Format: CGI/revision.
SERVER_PROTOCOL The name and revision of the information protocol this request came in with. Format: protocol/revision.
SERVER_PORT The port number to which the request was sent.
REQUEST_METHOD The method with which the request was made. For HTTP, this is "GET","HEAD","POST", etc.
PATH_INFO The part of the request URL, not counting the query string, following the name of the Zope installation or module published by ZPublisher.
PATH_TRANSLATED The server provides a translated version of PATH_INFO, which takes the path and does any virtual-to-physical mapping to it.
SCRIPT_NAME A virtual path to the script being executed, used for self-referencing URLs.
QUERY_STRING The information which follows the ? in the URL which referenced this script. This is the query information.
REMOTE_HOST The host name making the request. If the server does not have this information, it should REMOTE_ADDR and leave REMOTE_HOST unset.
REMOTE_ADDR The IP address of the remote host making the request.
AUTH_TYPE If the server supports user authentication, and the script is protected, this is the protocol-specific authetication method used to validate the user.
REMOTE_USER If the server supports user authentication, and the script is protected, this is the username under which it has been authenticated.
REMOTE_IDENT If the HTTP server supports RFC 931 identification, then this variable will be set to the remote username retrieved from the server.
CONTENT_TYPE For queries which have attached information, such as HTTP POST and PUT, this is the content type of the data.
CONTENT_LENGTH The length of the said content as given by client.
So now you have variables to display. Do it then. As they are a lot, just try one or two of them. Below codes would display all of those variables. I know you can just copy them, but well, you can only learn by doing, right ? By the way, some of these variables might not have any values at all, depending on your system. So if you some blank entries displayed, well, there is nothing wrong with script.
<table>
<tr>
<td>SERVER_SOFTWARE</td>
<td><dtml-var SERVER_SOFTWARE></td>
</tr>
<tr>
<td>SERVER_NAME</td>
<td><dtml-var SERVER_NAME></td>
</tr>
<tr>
<td>GATEWAY_INTERFACE</td>
<td><dtml-var GATEWAY_INTERFACE></td>
</tr>
<tr>
<td>SERVER_PROTOCOL</td>
<td><dtml-var SERVER_PROTOCOL></td>
</tr>
<tr>
<td>SERVER_PORT</td>
<td><dtml-var SERVER_PORT></td>
</tr>
<tr>
<td>REQUEST_METHOD</td>
<td><dtml-var REQUEST_METHOD></td>
</tr>
<tr>
<td>PATH_INFO</td>
<td><dtml-var PATH_INFO></td>
</tr>
<tr>
<td>PATH_TRANSLATED</td>
<td><dtml-var PATH_TRANSLATED></td>
</tr>
<tr>
<td>SCRIPT_NAME</td>
<td><dtml-var SCRIPT_NAME></td>
</tr>
<tr>
<td>QUERY_STRING</td>
<td><dtml-var QUERY_STRING></td>
</tr>
<tr>
<td>REMOTE_HOST</td>
<td><dtml-var REMOTE_HOST></td>
</tr>
<tr>
<td>REMOTE_ADDR</td>
<td><dtml-var REMOTE_ADDR></td>
</tr>
<tr>
<td>AUTH_TYPE</td>
<td><dtml-var AUTH_TYPE></td>
</tr>
<tr>
<td>REMOTE_USER</td>
<td><dtml-var REMOTE_USER></td>
</tr>
<tr>
<td>REMOTE_IDENT</td>
<td><dtml-var REMOTE_IDENT></td>
</tr>
<tr>
<td>CONTENT_TYPE</td>
<td><dtml-var CONTENT_TYPE></td>
</tr>
<tr>
<td>CONTENT_LENGTH</td>
<td><dtml-var CONTENT_LENGTH></td>
</tr>
</table>
Ok, so now you get the taste of the *name* attributes. Just remember this again, *name* attributes only display a content of a *variable*. It cannot do
calculation, retrieve value from object, etc (more on those later). It displays, and that's it. Another way to remember it, *name* attribute is a
*blonde*, just look, no brain.
Alright, alright, it can do something else. Just a bit more. It can *include* file. And call External Method (more on this later), but that's it. Promise.
<!--#var standard_html_header-->
Take a look at what we have here. This is what (one of many) you get when you create a new DTML document in Zope. As you see, it's still in old
DTML style tag. The equivalent, more modern, tag is
<dtml-var standard_html_header>
Ok, standard_html_header is a document. What above statement does is to include whatever the content in the standard_html_header document. You might not be able to find this document yet in your folder. So the document doesn't exist. Well, sort of. So how come the above statement works ?
Document standard_html_header and it's cousin, standard_html_footer, are supplied by default by Zope. If you want to override the HTML values that come with the standard "standard_html_header", create a document with the same name and supply it with with your own HTML configuration. Your *own* standard_html_header would be included instead of the default Zope one (How ? Acquisition, more on that later)
So, let's do an example.
- Create a new folder name "Felice" (In Italian, meaning = happiness).
- Inside "Felice", create a document with ID "main_content", and fill it with whatever text you want.
- Add this statement in the index_html (assuming you have it), somewhere in the document
<dtml-var main_content>
- Display your index_html, and magic, the content of the file "main_content" would be displayed. That's why I mean by *name* attribute does *include*.
So with this ability of *including* document, comes another powerful features called "Structured Text". In brief, this feature allows you to type a plain text file
in a certain matter, and the *var* tag would automatically format it in HTML. More on this later.
Expression.
Ok, so now you have done *name* attribute, which is not *really* clever. It's cousin, *expr* attribute, is so much clever and powerful.
This is how you declare a *var* tag with *expr* attribute.
<dtml-var expr="expression">
Unlike the *name* attribute, the enclosing doublequotes are compulsory. As with *name* attributes, there exists a short cut for expression.
<dtml-var "expression">
Notice the enclosing doublequotes around the expression. Because without the enclosing doublequotes, what would this statement becomes ? It becomes a *var* tag with *name* attribute. Remember ?
Try below statements to see one striking difference between *expr* and *name* attributes.
<dtml-var "SERVER_SOFTWARE">
<dtml-var SERVER_SOFTWARE>
This first statement would print out "SERVER_SOFTWARE", and the second one would print whatever value inside SERVER_SOFTWARE variable. See, the *expr* attribute just print the word "SERVER_SOFTWARE", the *name* attributes treats SERVER_SOFTWARE as a variable and try to display the content of the variable.
Let's do some math. The result would be displayed on the HTML page.
<dtml-var "1+1">
<dtml-var "20*2 +4">
<dtml-var "20/2">
<dtml-comment>
Btw, anything between this comment tag is considered as a comment.
<dtml-var "1+1"> would print 2
<dtml-var "20*2 +4"> would print 44
<dtml-var "20*(2+4)"> would print 120
<dtml-var "20/2"> would print 10
</dtml-comment>
Notice that you learn a new DTML tag, the comment tag. See that the comment tag comes in pair. The opening <dtml-comment> tag and closing </dtml-comment> tag.
Be careful especially with the latter tag, something you can easily make a mistake and type <dtml-/comment> instead.
Well, they are easy enough you say. How about the 'real' math support such as the famous cos,sin and family ? Well, they exist as well, in a so-called Zope built-in functions.
Special agent, no, variable _.
Yes. This special _ can only be used inside expression. It can do quite a lot of things and become the point of access to many Zope built-in functions. _ is actually an object (just accept it right now).
One of the function (it's actually a object method, but what the hell, let's call it function for a moment) is abs(X), which return an absolute value of a number.
Let's see how we use it.
<dtml-var "_.abs(-300)">
<dtml-var "2 * _.abs(23)">
<dtml-comment>
<dtml-var "_.abs(-300)"> would print 300
<dtml-var "2 * _.abs(-23)"> would print 46
</dtml-comment>
As you can see, you can perform the usual mathematical expression with the _ variable function.
And there are some other functions (methods) that you can use. Refer to ZQR (Zope Quick Reference) to get the complete list of functions.
[question -- should I list all functions here ? -- DG]
However, the _ variable doesn't stop here. There are some more specialised "modules" inside the _ variable. Those modules are
1. math Defines mathematical functions.
2. string Defines string functions.
3. whrandom Defines random-number generating functions.
To use the functions in these modules, a slightly different notation would be used. Add the module name in the access path.
<dtml-var "_.string.digits">
<dtml-var "_.math.sin(90) + _.math.cos(45)">
<dtml-var "_.math.pi * 90">
<dtml-var "_.whrandom.random()">
Btw, string.digits and math.pi are variables, they are not functions. That's why you don't see the "()" double brace sign.
For obvious reason, you cannot perform mathematical function on the string function.
The _ variable have some other methods that are useful in looking up variables, but the discussion on those methods would come later. The concept around the usage of those methods are quite hairy.
[question -- Is this enough coverage about name and expr? -- DG]
[question -- Is the previous material good enough ? -- DG]
Passing data
Now, we are getting into the common task that any dynamic web site need to do, passing data. There are many ways to pass data from the client browser to the server, you can do it thru form, url appending, or cookies.
Before we start with anything, let's talk about an object called REQUEST. If you don't understand what an object means, well, you can safely ignores it at this time. At this point, you just need to know on how to use it. REQUEST object handles all the data that passed by the client to the server. It does make thing easy because there is only one way to retrieve value from the client.
Just a reminder, as we are still in the realm of the *var* tags, we won't start to actually storing and using the values that are passed to the server. We would retrieve the values and display it.
If you are wondering on how to set up a 'local' variable, be patient, we will talk about it later.
Pass and use value thru form.
Let's start with a simple example. Create two new DTML document, textF and textA. Insert the listed statements between the standard codes you get when you create
a DTML document.
document id : textF
<form action="textA" method="post">
<input type="text" name="print">
<input type="submit">
</form>
document id : textA
<dtml-var "REQUEST.form['print']">
<dtml-comment>
Above one line code would display whatever string inputted in the form in textF document.
</dtml-comment>
<dtml-var "REQUEST.form['inputname']> is pretty much everything you need to know about retrieving values from a form.
But this doesn't end here. You know that <input type="text"> can be used to input a string or number(integer,float). The problem is, by default, Zope treats everything that come from a form as a string. As far as Zope concern, 3320 or 234 is a string.
Try this statement below
document id : textF
<form action="textA" method= "post">
<input type=text" name="distance">
<input type="submit">
</form>
document id : textA
<dtml-var "20 * REQUEST.form['distance']">
This one line above doesn't work. Why, because even if you say a number 21, Zope would convert 21 to a string, so well, you cannot perform mathematical operation
on a string. It doesn't generate errors. What it does is that it would print whatever number you put it (or any string for that matter), 20 times. This * multiplication feature for string come from the days of Python (the language Zope is written in).
So there must be another way to tell Zope what to do with values passed from a form (There is a term for this, type conversion).
So let's modify the statement in textF a bit. We want to 'tell' Zope that we want to have the value of distance field form to be treated as a integer.
document id : textF
<form action="textA" method = "post">
<input type="text" name="distance:int">
<input type="submit">
</form>
and try it again. Now, the statement in textA would properly multiply the number you've entered with 20.
Can you see, we just add ":int" after the name of the field, and Zope would convert the value in that form field as an Integer. The consequence is, if you don't enter a proper number in the field form, Zope would generate an error. So something like "340LS" or "KissMyButt" would generate an error. Now, Zope is expecting a number coming thru
that field form. (At this time, Zope would generate the standard error message, however, later in this book, you would learn on how to customise the error message)
This type conversion is not limited to integer though. There are quite many of type conversion that can be performed by Zope for your form.
These are some of the type conversion supported by Zope (taken from Trinket Tutorials)
float Float
int Integer
long Long integer
string String
required Non-blank string
text String with carriage-return newline pairs converted to newlines.
lines List of values separated by newlines.
tokens List of values entered as multiple space-separated tokens in a single field.
date Date Time instance
list List
tuple Tuple
record Record
ignore_empty Ignore empty
default default
records List of records
Let's try each on of them, and see what they do.
float,int, long
document id : textF
<form action="textA" method="post">
temperature : <input type="text" name="temperature:float"> <br>
wind speed :<input type="text" name="wind:int"><br>
pressure :<input type="text" name="pressure:long"> <br>
<input type="submit">
</form>
document id : textA
temperature : <dtml-var "REQUEST.form['temperature']"> <br>
wind speed : <dtml-var "REQUEST.form['wind']"> <br>
pressure : <dtml-var "REQUEST.form['pressure']"> <br>
<dtml-comment>
sample input: 58
output
float 58.0
int 58
long 58L
Float convert 58 (which is 'an integer') to float 58.0. No problem. However, if you put 58.0 in the wind speed field form (int), you would get an error.
</dtml-comment>
Another thing, try to submit the form without any entries. You will get an error stating that '' (empty string) is not an integer(or float, etc). However, if you are
expecting a string, empty string is considered as a valid string, albeit an empty one. You might not want this behaviour.
required,ignore_empty
document id : textF
<form action="textA" method="post">
Name : <input type="text" name="name:required">* <br>
Email : <input type="text" name="email:ignore_empty"><br>
<input type="submit">
</form>
document id : textA
<dtml-var "REQUEST.form['name']"> * <br>
<dtml-var "REQUEST.form['email']">
<dtml-comment>
The first statement (..form['name']) would generate an error if you don't enter any value to the form field. Well, that's the reason behind the name :required.
The last statement (..form['email']) would also generate error if you submit email field form without any value. Why ? This is because of the directive :ignore_empty
which tell Zope to remove the variable "email" from REQUEST object if the form field contains empty string. So, that's why (..form['email']) fails, because it doesn't exist as Zope concerned.
</dtml-comment>
Now, we mainly deal with form input of type "text". There are off course some other type of input form. Now, we would take a look of what kind of Zope type conversion do with the "textarea" type input.
text
document id : textF
<form action="textA" method="post">
<textarea name="description" rows="5" cols="60">
</textarea>
<input type="submit">
</form>
document id : textA
<dtml-var "REQUEST.form['description']">
Passing and manipulating cookie.
Reading cookie.
--------------A5DCA96ACA6DA20D7E7FBA37--