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.
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.
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.
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).
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.
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.
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 $. For example, you can reference a variable named n as
$n $(n) $n $n $(n)
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.
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.
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.
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 URLsThe 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: 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 At your discretion, you may choose to escape any character in a URL without changing its meaning. The following URLs are equivalent: 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.
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.
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.
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.
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.
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.
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.
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.
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.
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 ContextWhen 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." |
3.137.218.230