http://www.developer.com/

Back to article

Learning WML - Variables and Scripting


July 29, 2002

This series of articles describes how to provide Web content to mobile devices through WML (Wireless Markup Language). This article covers variables and beginning scripting with WMLScript. Future articles will cover more advanced scripting and how to integrate other technologies such as PHP to make your pages more flexible.

Note: These articles cover WML and WMLScript version 1.1, which are supported by the majority of mobile devices in use today. The articles assume a working knowledge of HTML and general Web technologies, and further assume that you have read the previous article(s) in this series.

Understanding Variables

WML supports variables that can hold transitional data between cards, provide custom output tailored to individual users, and more.

Variables are special holding places for values. They can hold numeric or alpha values and their values can be changed by code at the programmer's whim. However, it is usually good practice to dedicate variables to particular purposes, and hence, to particular types of data.

Variables in WML consist of words, enclosed in parentheses, prefixed with a dollar sign ($). For example:

     $(name)
     $(address)
     $(link)
     $(target_url)
     $(_method)

Note: Because the dollar sign ($) is used to signify a variable, it is a reserved character in WML. If you want an actual dollar sign to appear anywhere in your card(s), use a double dollar sign instead ("$$").

Variable names must start with a letter or underscore. Subsequent characters can be alpha, numeric, or underscores. Variables are case sensitive; "phone_number" is different from "Phone_Number."

Wherever a variable is referenced, WML will substitute the value of the variable where the variable name appears. For example, the following code:

<p>
     Hello $(name)!
</p>

would produce the following result, if "David" was stored in the variable $(name):

  Hello David!

Note: WML reserves the ampersand symbol (&) for entities. To use this symbol in your deck, you must substitute the corresponding entity "&amp;".

Setting Variables

Variables can be set by the following elements:

  <input>
  <select>/<option>
  <setvar>

Each of these elements is discussed in more detail below. Note that some of these elements were introduced in previous articles, and their parameters and such will not be detailed here.

The <input> Element

The <input> element is straightforward; it accepts user input and stores it in the variable specified. For example, the following code would accept input for a phone number and store it in the variable $(phone_number). The number is then displayed on the second card.

<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN"
 "http://www.wapforum.org/DTD/wml_1.1.xml"> 

<wml>

<card id="card1" title="Enter Number">
<do type="accept" label="Next">
     <go href="#card2" />
</do>
<p>
   What is your phone number?
   <input name="phone_number" 
             type="text" format="(NNN) NNN-NNNN" />
</p>
</card>

<card id="card2" title="Display Number">
<p>
     Your number is:<br/>
     $(phone_number)
</p>
</card>

</wml>

Note: The <input> element accepts a "value" attribute that can set a default value for the input. However, if the variable specified has already been assigned a value, the "value" attribute is ignored.

The <select> and <option> Elements

Each <option> element within a <select> can also set variables. When the user selects an option, that option's "value" parameter is stored in the variable specified by the select's name parameter. Although it sounds convoluted, it is pretty straightforward in practice. The following example would store the selected color's hex value in the variable "color":

<select name="color">
     <option value="#FF0000">Red</option>
     <option value="#00FF00">Green</option>
     <option value="#0000FF">Blue</option>
</select>

For example, if the user selected "Green," the variable "color" would be set to "#00FF00".

Note: The <select> element accepts a "value" attribute that can set a default value for the input. However, if the variable specified has already been assigned a value, the "value" attribute is ignored.

The <setvar> Element

The <setvar> element is perhaps the most pure of the variable-setting elements, because it serves the sole purpose of simply setting a variable. In the following example, the variable "color" is set to "Green":

  <setvar name="color" value="Green" />

The use of <setvar> is complicated by the fact that it can only be executed upon a <go>, <prev>, or <refresh> action. As such, you cannot simply embed a <setvar> anywhere you need to set a variable. It is common practice to set variables before moving to a card where you will need them, by embedding the proper <setvar> elements within the corresponding <go> or other action element.

If you need to set variables for the current card and doing so from a previous page is impractical (for example, for the first card displayed in the deck), you can use <onevent> and <refresh> elements to force a <setvar> to execute: For example, the following code will set the appropriate variables when the user enters this card from a forward direction:

  <card id="card1">
       <onevent type="onenterforward">
            <refresh>
                 <setvar . . . />
                 <setvar . . . />
            </refresh>
       </onevent>

Note: Unlike the other elements above, the <setvar> element sets the value of the specified variable whether or not it has previously been assigned a value.

Using Variables

Variables are very flexible and can be used in a variety of ways. You can store the results of user choices or status flags, display variable text, etc. Using the <postfield> element, you can even pass a variable's value to an external program.

The <postfield> element defines a name/value pair to be sent to the HTTP server with the next <go>. The <postfield> element is encapsulated within <go> elements as follows:

<go . . . >
     <postfield name="name" value="value" />
     . . .
</go>

The <go> element can include an optional "method" parameter that can be set to "get" or "post," which determines how the variable/value pairs are sent to the server. There are many differences between the two methods, but generally speaking "get" encodes the pairs in the calling URL while "post" sends the pairs in the body of the calling message. Of the two, "post" should be used wherever possible because it is more robust.

Using this method, you can pass values to CGI scripts or other external applications. For example, the following example passes the name/value pair color/Red to colorselect.cgi:

<go href="colorselect.cgi">
     <postfield name="color" value="Red" />
</go>

Note that the "value" attribute is mandatory and is not ignored if the variable has been set previously. To send a value of a variable that has been set elsewhere, use the variable tag as the "value" attribute. For example, the following code will send the current value of the color variable:

  <postfield name="color" value="$(color)" />

Note: You can also include variables in the URL of <go> and other navigation elements by using the standard "?name=value" notation:

  <go href="colorselect.cgi?color=$(color) />

As flexible as variables are, they only serve a static purpose on their own. Although you can store a variety of information, no decision-making ability is provided to set variables or make decisions regarding the status of variables within standard WML. However, you can extend the use of variables by using WMLScript to complement your WML code.

Beginning WMLScript Programming

WMLScript provides a means to add basic scripting to WML. WMLScript is similar to JavaScript-knowing JavaScript will certainly help you learn WMLScript. However, if you have any programming experience you should be able to learn WMLScript and be coding in no time.

Note: WMLScript does not translate to HDML. If you are creating pages that might be delivered to an HDML-compatible device (usually through a translation gateway), avoid using WMLScript.

Basic WMLScript Concepts

Although a full primer on WMLScript is outside the scope of these articles, it is important to understand a few basic concepts.

  • WMLScript is case sensitive. All language elements must be spelled using the proper capitalization of letters.
  • WMLScript supports integer, floating point, string, and Boolean literals. String literals must be enclosed in single or double quotes (' ' or " ") and Boolean values are set to "true" or "false."
  • WMLScript will automatically convert between values to deliver the right type of value (integer, string, etc.) to the function that receives the value.
  • Whitespace is ignored in WMLScript, allowing the programmer to format the code as desired.
  • Comments in WMLScript can consist of a single line or multiple lines. Single-line comments start with a double slash (//). For multiple-line comments, start the block with a slash followed by an asterisk (/*) and end the block with an asterisk followed by a slash (*/).
  • As with any language, WMLScript has a handful of reserved words such as "function," "var," "continue," etc. For a full list, consult the language guide for the version of WMLScript you are using.
  • You must declare all variables in WMLScript.
  • WMLScript can access variables set in WML. You can set a variable in a WML card and reference that same variable in a WMLScript. You can also pass values to WMLScript functions and return values from the function to the calling WML.
  • WMLScript is contained in external files (usually with a WMLS extension) and called from standard WML navigation elements using the following expression:

    <script filename>#<function name>(<arguments/parameters>)
    


    For example, to call the function "validate" in the file "validation.wmls" you would use
      validation.wmls#validate()
    

Your First Script

The easiest way to learn a scripting language is by example. The following basic example accepts a number, multiplies it by 2, and displays the result. This is a relatively useless script, but it helps simply to illustrate the mechanics between WML and WMLScript.

This example uses the following two files:

sample.wml

1.  <?xml version="1.0"?>
2.  <!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN"
 "http://www.wapforum.org/DTD/wml_1.1.xml"> 

3.  <wml>

4.  <card id="card1" title="Enter Number">
5.       <onevent type="onenterforward">
6.            <refresh>
7.                 <setvar name="num" value=""/>
8.            </refresh>
9.       </onevent>
10.  <p>
11.  <do type="accept" label="Multiply">
12.       <go href="sample.wmls#multiply()"/>
13.  </do>
14.  <input name="num" format="*N" />
15.  </p>
16.  </card>

17.  <card id="card2" title="Result">
18.  <p>
19.  Your number ( $(num) ) multiplied by 2 is:<br/>
20.  $(numX2)
21.  </p>
22.  </card>

23.  </wml>

sample.wmls

24.  extern function multiply() {
25.  var Num = WMLBrowser.getVar("num");
26.  var NumX2;

27.  NumX2 = Num * 2;
28.  WMLBrowser.setVar("numX2", NumX2);
29.  WMLBrowser.go("sample.wml#card2");
30.  }

Notice that the WMLScript file begins with an "extern" keyword in front of the function definition. This keyword allows a function to be accessed from outside the file; for this example, from our WML deck. Functions accessed internally by the same WMLScript file do not need this keyword.

Our example executes as follows:

  1. As the first card is displayed, the <onevent> handler causes the variable "num" to be initialized as blank (lines 5-9). Although not completely necessary, this step is good practice to ensure that the variable exists and is in a known state.
  2. Input is received via the <input> element and stored in the variable "num" (line 14). Note that the "format" parameter forces numeric input.
  3. The related <do> element (lines 11-13) calls the "multiply" function in the wmls file.
  4. The "multiply" function declares two variables, setting the variable "Num" to the value of the XML variable "num," by using the WMLBrowser.getVar function (lines 25-26).
  5. The variable "Num" is multiplied by 2; the resulting value is stored in the variable "NumX2" (line 27).
  6. The script stores the value of NumX2 into a WML variable ("numX2"), using the WMLBrowser.setVar function (line 28).
  7. The script uses a "go" function to jump to the second card in the WML deck (line 29).
  8. The second card (lines 17-22) displays our text, using the variables "num" and "numX2."

Note: The WMLBrowser library functions (WMLBrowser.setVar, etc.) provide an easy interface between XML and XMLScript. Consult a WMLScript language reference for more information on these functions.

A More Useful Script

One handy purpose for WMLScript is validating input and acting accordingly. For example, suppose we had a card that asked for a two-letter U.S. state abbreviation. Although the <input> element can ensure that we have two uppercase letters, it can't match the input against an acceptable list. For that, we will use WMLScript.

input.wml

<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN"
  "http://www.wapforum.org/DTD/wml_1.1.xml"> 

<wml>

<card id="state" title="Enter State">
     <onevent type="onenterforward">
     <refresh>
          <setvar name="stateabbr" value=""/>
     </refresh>
     </onevent>
<p>
     <do type="accept" label="Validate">
          <go href="validate.wmls#state()"/>
     </do>
     <input name="stateabbr" format="AA" />
</p>
</card>

<card id="stateok" title="StateValid">
<p>
     $(stateabbr) is a valid State code.
</p>
</card>

</wml>

validate.wmls

extern function state() {

var stateabbr = WMLBrowser.getVar("stateabbr");
var pos, x;
var okay = false;
var statelist =
  "ALAKASAZARCACOCTDEDCFMFLGAGUHIIDILINIAKS
KYLAMEMHMDMAMIMNMSMOMTNENVNHNJNMNYNCNDMP
OHOKORPWPAPRRISCSDTNTXUTVTVIVAWAWVWIWY";

if (String.length(stateabbr) == 2) {
  pos = String.find(statelist,stateabbr);
  x = pos / 2;
  if (Float.int(x) == x) { okay = true; } 
}

if (okay) {
  WMLBrowser.go("input.wml#stateok");
} else {
  Dialogs.alert("Invalid input!");
  WMLBrowser.go("input.wml#state");
}
}

The concept is relatively simple. The WML file takes the input, stores it in the "stateabbr" variable, and then calls the validation function. The function grabs the state abbreviation that was entered and performs two checks:

  • Is the abbreviation two characters long?
  • Does it appear in a valid list?

The String library function "length" is used to determine whether the abbreviation is two characters long. If so, the second check is performed. The second check attempts to find the abbreviation in the "statelist" string. The position is then divided by two-if the result is an integer, the state is valid.

Note: A simple substring search ("String.find") is not enough to validate the input, as combinations like "SK" would pass the test. The abbreviation must be in an even-numbered position (evenly divisible by 2). If the abbreviation is not found, the find function returns -1, which also fails the even number test.

More Information on WMLScript

A wealth of information can be found at the Openwave developer site, http://developer.openwave.com. Take a look at their Technical Library and be sure to visit the Developer Forum for answers to more difficult problems.

Next Time

The next article in this series will cover more WMLScript and how to integrate PHP into your WML.

About the Author

Steve Schafer is president and CEO of Progeny Linux Systems, a Linux-based consulting company in Indianapolis, Indiana. He has written several technical books and articles and can be reached at sschafer@synergy-tech.com.

# # #

Sitemap | Contact Us

Thanks for your registration, follow us on our social networks to keep up-to-date