Using Variables

WML supports programming variables within the body of the deck. A programming variable is simply a name associated with a data value. You can think of the variable as storing or containing that value.

Variables simply allow you to reference data by name within your WML decks. You can retrieve and change those values in response to browser events. You will typically use these variables to hold data that you retrieve from the user to alter the behavior of your application. These variables always reference string data and, by default, all uninitialized variables are empty strings.

Because the data you retrieve from the user is one of the most important pieces of an application, this section will detail the rules for working with WML variables. I will present the rules for naming, substitution, and manipulation of these variables.

Naming WML Variables

The rules for naming WML variables, much like the rest of the language, are very simple. First, the dollar sign character ($) starts off all variable references with the name of the variable immediately following.

Variable names can only contain the alphanumeric characters (a through z and 0 through 9) and the underscore (_). Both upper- and lowercase letters can be used (A through Z in addition to a through z). The first character in a variable name must be a letter or the underscore. The following are some examples of legal variable names:

$abc
$ABC
$_abc
$a_b_c
$ABC123
$A1b2C3

Each of these variables is distinct. Names are case sensitive, which means that $ABC can have a completely different value from $abc. Each variable is, of course, uninitialized by default and set to the empty string. The deck in Listing 7.1 demonstrates these variables in action.

Listing 7.1 Initializing and Referencing Properly Named Variables
<?xml version="1.0"?>
<!-- listing0701.wml -->

<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.2//EN"
    "http://www.wapforum.org/DTD/wml12.dtd">
<wml>
    <!-- attempt to reference properly named variables -->
    <card id="DemoGoodVar" title="Variable Use">

        <!-- initialize the vars each time on load -->
        <onevent type="onenterforward">
            <refresh>
                <setvar name="abc" value="lower case" />
                <setvar name="ABC" value="upper case" />
                <setvar name="_abc" value="1st underbar" />
                <setvar name="a_b_c" value="underbars" />
                <setvar name="ABC123" value="alpha, num" />
                <setvar name="A1b2C3" value="mixed" />
            </refresh>
        </onevent> 

        <!-- show the contents of each of the vars -->
        <p>
            abc = $abc<br/>
            ABC = $ABC<br/>
            _abc = $_abc<br/>
            a_b_c = $a_b_c<br/>
            ABC123 = $ABC123<br/>
            A1b2C3 = $A1b2C3<br/>
        </p>
    </card>
</wml>

The simple deck in Listing 7.1 uses the <setvar> initialization tag to assign a value to each of the well-named variables I presented. The only paragraph on the card displays, line-by-line, the contents of each of the variables as shown in Figure 7.1.

Note

I cover the syntax of the <setvar> tag later in this chapter. Chapter 5, "Managing Output," covers the formatting of the paragraph in detail, including the use of the <br> tags to create a lightly formatted card.


Figure 7.1. Properly named variables in action.


In addition to the acceptable format for names, I often find it helpful to know what is unacceptable and see some counterexamples. You cannot use any whitespace in a variable name; you cannot use any punctuation in a name; you cannot begin or any characters that are not US-ASCII (sorry non-English developers). The following are examples of variable names that the browser will not accept:

$Bad Var
$1BadVar
$Bad-Var
$-BadVar
$ BadVar
$BådVär

In this list, I present a bunch of variables that will cause browsers to choke on a deck that attempts to include any of them. The actual error that appears to the user will depend on the browser he or she uses; most simulators will provide details on what the error is and where it occurred in your source code. The deck in Listing 7.2 illustrates using poorly formed variables (as far as it can, that is).

Listing 7.2 Initializing and Referencing Improperly Named Variables
<?xml version="1.0"?>
<!-- listing0702.wml -->

<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.2//EN"
    "http://www.wapforum.org/DTD/wml12.dtd">
<wml>
    <!-- attempt to reference poorly named variables -->
    <card id="DemoBadVar" title="Bad Variable Use">

        <!-- initialize the vars on each load -->
        <onevent type="onenterforward">
            <refresh>
                <setvar name="Bad Var" value="Good Value" />
                <setvar name="1BadVar" value="1GoodValue" />
                <setvar name="Bad-Var" value="Good-Value" />
                <setvar name="-BadVar" value="-GoodValue" />
                <setvar name="Bad Var" value="Good Value" />
                <setvar name=" BadVar" value=" GoodValue" />
                <setvar name="BådVär" value="GoodVälue" />
            </refresh>
        </onevent>

        <!-- show the contents of the vars that don't -->
        <!--  cause browser errors                    -->
        <p>
            Bad Var = $Bad Var<br/>
            1BadVar = <!-- $1BadVar -->error<br/>
            Bad-Var = <!-- $Bad-Var -->error<br/>
            -BadVar = <!-- $-BadVar -->error<br/>
            &nbsp;BadVar = <!-- $ BadVar -->error<br/>
            BådVär = <!-- $BådVär -->error<br/>
        </p>
    </card>
</wml>

The deck in Listing 7.2 is also quite simple. It attempts to use the <setvar> tags to initialize the poorly named variables and then display their contents in the body of the card. Most browsers will accept the deck and produce a display similar to the simulator shown in Figure 7.2.

Figure 7.2. Poorly named variables in action.


The <setvar> tags in Listing 7.2 do not cause many problems for the browsers, even with the malformed name attribute values. The body of the card, however, generates parsing errors when the browser attempts to reference the variables. I wrapped each reference that caused parsing problems with a comment tag (<!-- -->) and added the text "error" in place of the actual value. The most interesting of the bad variable names is probably the one called $Bad Var; the browser interprets the whitespace between words as the termination of the variable name. It displays the contents of the uninitialized $Bad variable and then displays the word Var.

Note

The comment tag, <!-- -->, creates an XML comment that will be stripped out by the XML parser before being transmitted to the browser by the WAP gateway. Placing these comments in your source code does not impact your application's performance in any significant way, but the practice will help you communicate your ideas to anyone who maintains your code in the future.


To denote the start and termination of variable names, WML lets you place parentheses around them. The reference $(var) is equivalent to the reference $var. You might run into this when you place variable contents in output text. The deck in Listing 7.3 demonstrates a potential problem and how parentheses solve it.

Listing 7.3 Using Parentheses Around Variable References
<?xml version="1.0"?>
<!-- listing0703.wml -->

<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.2//EN"
    "http://www.wapforum.org/DTD/wml12.dtd">
<wml>
    <!-- show the use of parentheses for separating   -->
    <!--  variables from content                      -->
    <card id="DemoVarParens" title="Variable Parens Use">

        <!-- initialize the balance vars on load -->
        <onevent type="onenterforward">
            <refresh>
                <!-- balance in hundreds -->
                <setvar name="CBal" value="50" />
                <setvar name="CBal00" value="50" />
            </refresh>
        </onevent>

        <!-- show the current balance with and without -->      
        <!--  parentheses, the first line will display -->      
        <!--  the proper amount, the second one won't  -->      
        <p>
            Your balance $(CBal)00<br/>
            Your balance $CBal00
        </p>
    </card>
</wml>

The deck in Listing 7.3 shows you a very contrived example, which illustrates the utility of the parentheses around variable names. Because whitespace (tabs, line feeds, or spaces) delimits variables for the browser, when you need to reference a variable adjacent to other text, you must tell the browser where its name ends and the other text begins.

Even though the example in Listing 7.3 demonstrates an obviously incorrect result, it's unusual. Often, the variable referenced through incorrect code does not exist, and the browser replaces it in the output with an empty string. This empty string bug is easy to create but hard to detect in practice.

Tip

You should get into the habit of always surrounding your variables with the parentheses, using the $(var) syntax. This practice only costs you a couple of keystrokes and bytes in deck size before the WAP gateway translates it. After the card is compiled, it costs you nothing on the slow connection from the gateway to the device. That cost is typically insignificant when compared to the savings in debugging and maintenance efforts.


Finally, to wrap up the discussion on WML variable naming, I need to remind you that variable names are browser-side artifacts. This means that these names mean nothing to the XML parser at the WAP gateway; they are simply #PCDATA. This means that you can replace the dollar sign that begins the variable with an XML entity reference such as &#x24;. For example, you can reference a variable named n as

$n
$(n)
&#x24;n
&#x24;&#x6E;
&#x24;&#x28;n&#x29;

It is the responsibility of the XML parser to replace each of the entities with their characters, $n or $(n), in the WML source code. After the characters have been placed in the source and delivered to the client, the browser will interpret them as a variable named n. The next section will show you how to take advantage of these variables in your decks.

Substitution

The string referenced by a variable name can be substituted into a WML deck anywhere #PCDATA or the %vdata; and %HREF; entities are accepted. This means the text bodies of paragraphs, most attribute values on most tags, and all URLs (Uniform Resource Locators) used on your decks. You can look in the DTD for places that will accept substituted variables, for example

<!ELEMENT a ( #PCDATA | br | img )*>
<!ATTLIST a
    href %HREF; #REQUIRED
    title %vdata; #IMPLIED
    accesskey %vdata; #IMPLIED
    xml:lang NMTOKEN #IMPLIED
    %coreattrs;
>

The <a> tag supports variable substitution in its body, in the URL of its href attribute, and its title attribute. The example in Listing 7.4 shows this in action.

Listing 7.4 Substituting Variables into a Link Tag
<?xml version="1.0"?>
<!-- listing0704.wml -->

<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.2//EN"
    "http://www.wapforum.org/DTD/wml12.dtd">
<wml>
    <!-- show the substitution of variables in a link -->
    <card id="DemoVarSubst" title="Variable Substitution">

        <!-- initialize the link vars on load -->
        <onevent type="onenterforward">
            <refresh>
                <setvar name="LinkDest"
                    value="Listing0705.wml" />
                <setvar name="LinkBody"
                    value="Next Example" />
                <setvar name="LinkTitle"
                    value="Listing 7.05" />
            </refresh>
        </onevent>

        <!-- use the variables that we just setup to create -->
        <!-- a useful hyperlink                             -->
        <p>
            <a href="$(LinkDest)" title="$(LinkTitle)">
                $(LinkBody)
            </a>
        </p>
    </card>
</wml>

The deck in Listing 7.4 shows the construction of a link tag that has all three types of escapement areas: %HREF;, %vdata;, and #PCDATA. The browser escapes the href attribute but not the title attribute nor the body of the link. This deck, as shown in Figure 7.3, works properly and links to the next example.

Figure 7.3. Default escapement of client variables.


This means that you can place dynamically created text almost anywhere you can place hard-coded text. You cannot place WML tags or additional attributes in the variables; the browser will not substitute them and create the behavior you are trying to accomplish.

Note

You cannot set attributes that require enumerated values, such as the align attribute of a <p> tag, with variable substitution. For example, the following tag will cause a compilation error at the WAP gateway:

   <p align="$(MyAlignment)">

Chapter 5 has more details on the <p> tag and its attributes.


Depending on where you direct the browser to substitute variables, you can specify text conversions. With the WML text conversion facilities, you can either escape or unescape characters to use or display URLs.

Special Characters in URLs

The IETF RFC 2396 specifies the rules for URLs, which are a subset of URIs (Uniform Resource Identifiers). You can find the full text of the RFC at http://www.ietf.org/rfc/rfc2396.txt; section 2 covers characters and escape sequences.

The character set for URLs is US-ASCII. There is currently no standard provision for other character sets.

URLs require certain characters to separate their components. For example, the protocol is separated from the machine name by the :// sequence in http://foo.com/. These special characters are termed reserved by the URL specification and include the characters :, /, ?, ;, @, &, =, +, $, and ,. When placing these characters in a URL, you must replace them with their equivalent, escaped values. For example, the following URL is not legal:

http://foo.com/COM+

URL escapement simply replaces any character with its US-ASCII hex values in the form %HH where HH are the digits. For example, the question mark (?) character has ASCII decimal value 63 and hex value 3F. You can replace it in a URL with %3F or %3f (the escapement is not case sensitive). The proper construction of the previous COM+ URL is

http://foo.com/COM%2B

At your discretion, you may choose to escape any character in a URL without changing its meaning. The following URLs are equivalent:

http://foo.com/bar

http://foo.com/%62%61%72

Most of the remaining US-ASCII character set that is neither numbers nor alphabetic characters also require escapement. I could enumerate each of the ones that require escapement, but it would only leave a small set that I have not covered. A good rule of thumb is to escape any non-alphanumeric characters when constructing a URL.


To help you construct and display URLs in your decks, the WML browser gives you first-class access to the URL escapement mechanism. The browser will do this escapement and unescapement for you implicitly, depending on the type of substitution you attempt. Alternatively, you may chose to be explicit about using variable modifiers.

To use the explicit substitution modifiers, you simply place them after a colon and the variable name inside the variable's parentheses. That is, the syntax is $(var:esc) where esc is one of the escapement values in Table 7.1.

Table 7.1. Variable Escaping Modifiers
Modifier Behavior
(none) Apply the default escapement for the context.
noesc Do not apply any escapement to the variable, regardless of the context.
escape Apply URL encoding to the string before using it in the current context.
unesc Reverse URL encoding from the string before using it in the context.

By default, variables substituted into #PCDATA will not be URL-escaped by the browser. This means that non-alphanumeric characters in the strings will not be replaced with their %HH equivalents.

Likewise, variables that you substitute into %vdata; attributes will not be automatically URL-escaped by the browser. By default, the browser will URL-escape all variables you substitute into %HREF; attributes. The deck in Listing 7.5 demonstrates explicit variable escaping.

Listing 7.5 Explicitly Specifying Variable Escapement
<?xml version="1.0"?>
<!-- listing0705.wml -->

<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.2//EN"
    "http://www.wapforum.org/DTD/wml12.dtd">
<wml>
    <!-- show the escapement and substitution of variables -->
    <!--   in a link                                       -->
    <card id="DemoVarEsc" title="Var Escapement">

        <!-- initialize the link vars on load -->
        <onevent type="onenterforward">
            <refresh>
                <setvar name="FooBar"
                    value="http://foo.com/%62%61%72" />
           </refresh>
        </onevent>

        <!-- show the escapement of the URL variable -->
        <p mode="nowrap">
            <small>
                <!-- use the full href unescaped (works) -->
                <a href="$(FooBar:unesc)">
                    $(FooBar:unesc)
                </a>
                <br/>
                <!-- use the full href raw (works) -->
                <a href="$(FooBar:noesc)">
                    $(FooBar:noesc)
                </a>
                <br/>
                <!-- use the full href escaped (fails) -->
                <a href="$(FooBar:escape)">
                    $(FooBar:escape)
                </a>
            </small>
        </p>
    </card>
</wml>

The example in Listing 7.5 shows a variable that represents a URL with escaped characters. The first link on the page unescapes the special characters in the URL using unesc and creates a link that is readable by both the browser and the user; this link is operational.

The middle link in the card disables the escapement with the noesc modifier; this link is less readable to humans, but still readable to the browser. It is also an operational link. The final link on the page mimics the default behavior of the browser and replaces all non-alphanumeric characters in the variable with equivalents.

In Figure 7.4, you can see that the last link has escaped the :// portion of the URL due to the escapement of variable. Although not shown in the figure, further to the right of the URL the browser replaced the original percent signs (%) that precede the escapement of bar with their own %25 escapements.

Figure 7.4. Explicit escapement of client variables.


When using variables in %HREF; attributes, you must be wary of the double-escapement problem. Now that you know the ins and outs of referencing variables in your decks, let's move on to setting them up.

Manipulation

As you've seen throughout this chapter, you can use the <setvar> tag to change the value of a variable. This tag's syntax is very simple, as seen from the DTD snippet:

<!ELEMENT setvar EMPTY>
<!ATTLIST setvar
    name %vdata; #REQUIRED
    value %vdata; #REQUIRED
    %coreattrs;
>

When the browser encounters one of these tags, it simply stores the string from the value attribute in a memory location that you can then reference with the name attribute. This allows you to initialize or change the value of a variable anytime you can force the browser to execute the tag.

Delivering <setvar> Tags with <refresh>

In order to deliver a setvar element to the browser and instruct it to change the contents of a variable, you must wrap it in a go, prev, or refresh element. You will typically use the first two elements in direct response to a user action such as pressing a soft key to select a link.

The refresh element, as you can see from the following DTD snippet, is very simple:

   <!ELEMENT refresh (setvar)*>
   <!ATTLIST refresh
       %coreattrs;
   >

This element is simply a grouping mechanism that you will use to instruct the browser to change the data simultaneously. That is, before executing any other part of your deck, the browser will execute each assignment.

Following the variable assignments, the browser saves the data into its current context and starts any timer element the card might contain. Finally, the browser must re-display the current card with the new variable state, hence the name for the element.


You should also note from the DTD snippet that both the name and value attributes are of type %vdata;. This means, as shown in the previous section, that you can substitute variables into each of the attributes. The deck in Listing 7.6 demonstrates the use of the <setvar> tag both with hard-coded and dynamic data.

Listing 7.6 Setting Variables Using the <setvar> Tag
<?xml version="1.0"?>
<!-- listing0706.wml -->

<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.2//EN"
    "http://www.wapforum.org/DTD/wml12.dtd">
<wml>
    <!-- demonstrate the use of the servar tag -->
    <card id="DemoVarSet" title="Var Setting">

        <!-- let the use set the vars -->
        <do type="options" label="Set Vars">
            <refresh>
                <setvar name="Var1" value="Value1" />
                <setvar name="Var2" value="$(Var1)" />
                <setvar name="$(Var2)" value="Value2" />
           </refresh>
        </do>

        <!-- show variables (requires keypresses) -->
        <p mode="nowrap">
            <small>
                Var1: $(Var1)<br/>
                Var2: $(Var2)<br/>
                Value1: $(Value1)<br/>
            </small>
        </p>
    </card>
</wml>

The deck in Listing 7.6 sets three distinct variables using the <setvar> tag. The first tag assigns the Var1 variable to Value1; these are both hard-coded attributes. The second tag assigns the value of the Var1 variable to the Var2 variable, forcing them both to have a value of Value1.

Finally, the third variable set in the deck from Listing 7.6 assigns the variable named by the contents of the Var2 variable (Value1) to Value2. Figure 7.5 shows the results of this card.

Note

To achieve the same results as shown in Figure 7.5, you will have to press the key labeled Set Vars three times.


Figure 7.5. Variable setting using the <setvar> tag.


The <setvar> tag can only be placed within the <go>, <prev>, and <refresh> tags on the card. Of course, these tags must be children of <do>, <onevent>, and <anchor> tags, which all directly respond to user input. This gives you the opportunity to dynamically change the contents of your variables in response to a user action.

▸ See Chapter 4, "Card Navigation," for details on moving between cards with the <go> and <prev> tags.

To illustrate setting variables in response to user action, Listing 7.7 creates a pair of cards that modify a variable as the user navigates between them. You can use this type of simple variable setting to track a user's navigation.

Listing 7.7 Tracking Navigation Through Variables
<?xml version="1.0"?>
<!-- listing0707.wml -->

<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.2//EN"
    "http://www.wapforum.org/DTD/wml12.dtd">
<wml>
    <!-- variable setting on keypresses and navigation -->
    <card id="Card1" title="Var Display">

        <!-- when entering the deck for the first time, -->
        <!--   initialize the state variable            -->
        <onevent type="onenterforward">
            <refresh>
                <setvar name="State" value="Initial" />
            </refresh>
        </onevent> 

        <!-- when entering the card from the second card, -->
        <!--   say so in the state variable               -->
        <onevent type="onenterbackward">
            <refresh>
                <setvar name="State" value="Returned" />
            </refresh>
        </onevent> 

        <!-- when leaving the card for the second card, -->
        <!--   say so in the state variable             -->
        <do type="accept" label="Change">
            <go href="#Disp">
                <setvar name="State" value="Changed" />
            </go>
        </do>

        <!-- allow the user to clear out the state  -->
        <do type="reset" label="Clear">
            <refresh>
                <setvar name="State" value="Cleared" />
            </refresh>
        </do>

        <!-- tell the use the current state -->
        <p>
            Card #1 current state: $(State)
        </p>
    </card>

    <!-- a second card to display the state of the variable -->
    <card id="Disp" title="Var Display">
        <p>
            Card #2 current state: $(State)
        </p>

        <!-- allow the user to return to the previous card -->
        <do type="accept" label="Return">
            <prev/>
        </do>
    </card>
</wml>

The deck in Listing 7.7 creates and manipulates the variable named $(State) across two cards. When the card browser first displays the card, it executes the <onevent> tag for "onenterforward", which assigns "Initial" to $(State). The card also assigns actions to two buttons: one that takes the user to the other card and another that clears out the state variable.

As you can see from the cards in Figure 7.6, using the soft keys triggers events on the first card that modify the value of the $(State) variable. This variable maintains a trace of the user's last action; possible values include Initial, Changed, Returned, and Cleared.

Figure 7.6. Variable setting during card navigation.


To this point, the variable setting that I have shown you has placed hard-coded values into variables and consumed them within the deck. This variable use forms the foundation for all dynamic input; the rest of the chapter will use these techniques to gather directed information from application users.

Variable Lifetime and Browser Context

When setting values into a variable within a card, you should be aware of the lifetime of that data. It turns out that this lifetime is quite different than that of a variable in an HTML browser. To understand what happens, let's start with the concept of the browser context.

The browser context includes all known variables, navigation history, and anything else the browser wishes to keep around; it's essentially all of the browser's dynamic memory. This context is shared by all cards in all decks unless specifically reset. That is, any of the context information set in one card or deck may be seen by another deck, possibly from another application.

This shared context will probably be quite a shock if you've developed HTML pages in the past. In HTML, all variables had life only during the display of the page; once the page was unloaded, so was all of the data. In WML, another deck can come along and snoop through the data your deck left behind.

You can ask the browser to clear out its context using the newcontext attribute of the <card> tag. This attribute can be either true or false and defaults to false when not specified. While the newcontext attribute sounds promising, it's a bit lackluster since WML only requires that this be honored when it loads your card from another card's <go> tag.

To guarantee that you don't pick up another deck's data and it cannot pick yours up, you should go through a rigorous cleaning regimen on entry and exit from each card, especially when the card gathers sensitive data. I cover such a technique in Chapter 12, "Securing Applications."


..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.137.218.230