WML基本情況
WML----Wireless Markup Language
WML是XML的子集。WML文件以*.wml命名。WML文件必須滿足XML文檔的規則。
WML文檔通常使用XML解釋器解釋。
WML文檔編輯環境
編輯器---WML本身是文本,所以任何文本編輯器都可以完成。
模擬器---NOKIA ERICSSON MOTOROLA等都可以。
圖形轉換--製作適合WAP的圖片,pic2wbmp。
文字轉換--漢字<-->UNICODE UTF-8。
WML文件結構
WML文檔頁面通常叫做桌面(DECK),由一組互相連接的卡片(CARD)組成。
當移動設備訪問WML的一個頁面,頁面所有的CARD都下載到WAP設備裏面。CARD的切換由電話內置的設備處理,不再從服務器上取信息了。
CARD可以包含文本、標記、鏈接、輸入控制、任務(TASK)、圖像等等。
文檔包含在下面的格式裏面:
實體--<xml>...</xml>
CARD--<card>...</card>
文字--<p>...</p>
簡單例子:
<?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="HELLO" title="HELLO">
<p>
Hello world!
</p>
</card>
</wml>
顯示結果如下:
------ HELLO ------
Hello World!
WML字符集:
WML是XML的子集,繼承了XML的字符集設置。
WML文檔缺省的字符集是UTF-8。
要顯示中文有兩種方式:
1、在前面指定字符集,但是目前不支持,具有關人士說,CDMA的手機都已經基本上支持;
<?xml version="1.0" encoding="gb2312"?>
2、使用UNICODE代碼來代表中文:
<b>&#x
代表:
通訊錄
WML元素:標記(Tag)和屬性
由於標記會降低WAP設備的通訊速度,所以WML標準裏面僅僅使用了很少的一部分,大部分還是文本。
用於表格和圖像的標記基本上都被忽略了。
<tag>內容</tag> 例如:<p>Hello world!</p>
或
<tag/> 例如:<br/> 和 <go href="#done"/>
WML同樣支持標誌中標出屬性。屬性不在屏幕上顯示出來。
WML標記和屬性的值都是大小寫敏感的(<xml>和<XML>是不一樣的),而且標記必須嚴格按照xml的標準結束。
WML要求屬性的值必須放在雙引號或者單引號內。單引號可放在屬性標誌內或者雙引號內。
字符也可以爲屬性的值。
WML註釋
XML支持的註釋格式:
<!You can not see this missage--->
WML不支持嵌套元素註釋。
鏈接(URL)
WML外部引用方式跟HTML相同
http://www.wap86.net/great.wml 或
http://www.wap86.net/great.wml#login
如果是內部引用,如果next是當前的DECK中的一個CARD時,可以使用這種方式:
#next
提供鏈接的WML元素有2個:<go>和<anchor>。
CDATA
XML支持CDATA的概念,顯示不需要解釋的文本信息。
<! [CDATA [ <card name="bogus"><p>this is data</p></card> ] ]>
瀏覽器窗口將顯示如下內容:
<card name="bogus"><p>this is data</p></card>
格式
定義變量:
$identifier |
變量的字符串級別最高,如果遇到相同的字符串,首先被認爲是變量。顯示$,需要後面在跟一個,$$。例如:
You account has $$ |
變量名稱規則:
1、變量名是由US-ASCII碼、下劃線和數字組成;
2、只能以US-ASCII碼開頭;
3、變量名大小寫敏感。
注意:
1、WML變量沒有類型,均表示爲字符串;
2、變量沒有被賦值的時候,內容爲空,即空字符串。
3、可以在運行過程中改變它的值。
創建變量
最簡單的方法是使用<setvar>元素,語法如下:
<setvar name="string" value="string" /> |
<setvar>只能在<go>、<prev>和<refresh>中使用。
下例定義了一個叫vNAME的變量並賦值爲“Jeff”:
<setvar name="vNAME" value="Jeff" /> |
另外,還可以在<input>、<select>和<postfield>中定義變量。
替換文本
變量可以用作替換用途,但只能在文本類型(如顯示字符、URL等)中使用。
任何元素和屬性都不能使用變量來替代。例如:
Hello, $vNAME. |
將顯示:
Hello, Jeff. |
ESCAPE轉換
前面說過變量可以用作替換用途,但是在URL中使用時,變量的內容必須遵守[RFC2396]標準。
這個標準規定某些特殊字符在URL裏使用的時候必須用特殊表示方法,即ESCAPE八進制表示。
例如:
list.asp?id=3 |
在URL中要表示爲:
list.asp%3fid=3 |
所以變量有可能需要標誌爲是否對其內容進行ESCAPE轉換,變量定義就有如下幾種特殊方式:
效果 |
表達方式1 |
表達方式2 |
表達方式3 |
對變量中ESCAPE字符進行轉換 |
$(var:e) |
$(var:E) |
$(var:escape) |
不進行ESCAPE轉換 |
$(var:u) |
$(var:U) |
$(var:unesc) |
變量中沒有ESCAPE字符 |
$(var:n) |
$(var:N) |
$(noesc) |
給變量進行ESCAPE轉換是WML的默認方式。
CARD裏可以顯示象文本、圖像這樣的內容。
段落與換行標記
<p>:段落標記,用來對段落進行分段。語法:
<p |
aligh:文字對齊方式,左(left)、右(right)、居中(center)。
mode:文字超出屏幕時是否折行,各種終端處理方式不同。
xml:lang:顯示語言編碼。
<br>:行分隔標記,產生回車效果。
語法:
<br |
xml:lang:顯示語言編碼。
段落和換行的例子:
<?xml version="1.0"?> |
顯示結果如下:
------ Paragraphs ------ |
標記 |
字體樣式 |
<b> |
粗體 |
<big> |
大字體 |
<em> |
強調字體 |
<i> |
斜體 |
<small> |
小字體 |
<strong> |
加重強調字體 |
<u> |
下劃線字體 |
文字樣式標記
WML提供了一系列文字樣式的標記,如右表所示。不過WML鼓勵大家儘量使用<strong>和<em>標記,因爲某些WAP終端會忽略其他標記。
每個文字樣式標記語法都一樣,都有一個標誌語言代碼的xml:lang屬性。
下面是一個例子:
<?xml version="1.0"?> |
在你的終端上可能會有這樣的顯示:
list.asp%3fid=3 |
所以變量有可能需要標誌爲是否對其內容進行ESCAPE轉換,變量定義就有如下幾種特殊方式:
----- Formatting ----- |
表格
WML支持簡單的表格標記<table>、<tr>和<td>。語法如下:
<table |
在WML裏定義一個表格必須先指定列數,即columns屬性。而在表格裏就必須有相應數量的<td></td>標記對。因該注意的是,align(對齊)屬性的內容只能是L(左對齊)、R(右對齊)和C(居中),跟其他標記不同(是不是有點怪?)。
下面的例子演示了表格的基本功能:
<?xml version="1.0"?> |
顯示結果(注意WML裏沒有表格線):
------ SALARY ------ |
圖像
WML支持WBMP(Wireless Bitmap)格式的圖像,需要用特殊工具製作。
顯示圖像使用<img>標記,語法如下:
<img |
alt: 圖像無法顯示時的替換文字。
src: 圖像的url。
localsrc: 儲存於ROM(或RAM)中圖像的名字,各種終端支持不同。
align: 上下對齊方式。
height: 圖像顯示高度。
width: 圖像顯示寬度。
hspace: 圖像左右的空白,以pixel數或百分比表示。
vspace: 圖像上下的空白,以pixel數或百分比表示。
上面的屬性只有alt和src是必須的。其他附加屬性基本上僅僅用來指示用戶終端,大多數情況下會被忽略。下面是個例子:
<?xml version="1.0"?> |
下面分別是在支持和不支持圖像的終端上的顯示結果:
|
|
桌面 (DECK)
由於網絡帶寬以及某些WAP服務器DECK傳輸的限制,DECK越小越好,最好不要超過1.2K。
如果DECK很複雜那就分成多個DECK完成。
完整的WML文檔結構如下:
<?xml version="1.0"?> |
XML說明
DECK開頭必須指明以下的XML類型聲明:
<?xml version="1.0"?> |
第一行指出XML版本,緊跟的文檔類型(DOCTYPE)聲明指出所引用的語言標準定義。
這兩句的位置和順序不可更改,而且中間不能有空行。
<wml>
語法
<wml>標籤和HTML中的<html>標籤一樣,用來表明這是一個WML的DECK。xml:lang屬性來指定文檔的語言,比如<wml xml:lang="zh">表示文檔語言爲中文。
<head>
<head>標籤包含了該DECK的相關信息。<head>標籤之間可以包含一個<access>標籤和多個<meta>標籤。
<access>
<access |
<access>相當於HTML中的<BASE>標籤,指定該DECK的訪問控制信息,它的兩個屬性是可選的。
domain:指定域,默認值爲當前域。
path:指定路徑,默認值爲"/",即根目錄。
<meta>語法:
<meta |
和HTML中<META>的類似,<meta>提供了該DECK的meta信息。
包括一下三種情況
name="name" UP.Link Server忽略meta數據
http-equiv="name" UP.Link Server將meta數據轉爲HTTP響應頭(同HTML)
user-agent="agent" UP.Link Server直接將meta數據傳給手機設備
content屬性也是必選的,其內容根據屬性而定。scheme屬性目前尚不支持。forua爲可選屬性,指定在該wml文件傳到客戶端之前,<meta>標籤是不是被中間代理刪除(因爲傳輸的協議可能改變),默認值爲false。
目前支持的meta數據:
<meta http-equiv="Cache-Control" content="max-age=3600"/>指定DECK在手機內存緩存中的存儲時間段,默認的爲30天(除非內存耗盡),在該期間,手機對於訪問過的DECK直接從緩存裏調用。如果信息是對時間敏感的,可以用max-age指定DECK在緩存裏的生存期,最小單位是秒,如果指定爲0,則每次都需通過連接服務器來調用該DECK。
<meta user-agent="vnd.up.markable" content="false"/>和<meta user-agent="vnd.up.bookmark" content="指定的URL"/>類似於普通瀏覽器的書籤功能。
當用戶將一個CARD做了書籤後,手機瀏覽器首先用一個標記記錄該CARD,這個標記默認的是<card>標籤中的title屬性(以後會講到),然後當用戶選擇了該書籤以後,瀏覽器就會打開被記錄的URL。
但是因爲在默認的情況下,手機會記錄所有的DECK,所以,一般<meta>被用來使手機不要記錄當前的URL,即<meta user-agent="vnd.up.markable" content="false"/>。
此外,如果要爲書籤指定不同於當前DECK的URL,用<meta user-agent="vnd.up.bookmark" content="指定的URL"/>。
<template>
<template>元素聲明一個DECK級的事件/請求,對DECK頁面中所有CARD有效,當然某個CARD可以通過定義同名的事件來替代<template>聲明中的事件處理。
語法:
<template |
onenterforward:當用戶通過<go>進入CARD時調入的鏈接。
onenterbackward:當用戶通過<prev>退回CARD時調入的鏈接。
ontimer:<timer>事件激活時調入的鏈接。
例子:
<wml> |
<card>
一個DECK可以包含多個CARD,每個CARD的內容可能不止一屏顯示,注意DECK、CARD和屏幕顯示範圍的關係。一個CARD用<card>和</card>包含。
語法:
<card |
每個CARD元素可以有一個標號(ID)和標題(TITLE)。當然,這都不是必須的。
id:CARD的名字,在DECK中唯一,可用作URL已進行跳轉。
title:CARD的標題,用戶BOOKMARK一個CARD時的名字。該屬性在某些用戶終端上會顯示出來。
newcontext:用來指示當跳轉到本CARD時,用戶終端(手機、模擬器等)是不是要清除以前保留的信息如變量、堆棧歷史記錄、終端狀態等。默認值爲FALSE。
ordered:表明該CARD裏的內容是按固定的順序顯示,還是按用戶的選擇來顯示。默認值是TRUE。這點和HTML不同,CARD頁面裏的內容可以按一定的順序顯示,默認的是按線性順序顯示,即按代碼的順序,但是,要注意的是,以下三個標籤必須按以下順序來寫<onevent> <timer> <do>。這樣做是爲了方便填表單,當ordered設置爲true時,如果一個表單的內容不能在一屏裏顯示完,就分成多屏顯示;當ordered設置爲false時,手機可以顯示一個概要CARD來總結有效的選項,用戶可以從中選取表單選項來填寫。
onenterforward:當用戶通過<go>進入CARD時調入的鏈接。
onenterbackward:當用戶通過<prev>退回CARD時調入的鏈接。
ontimer:<timer>事件激活時調入的鏈接。
不同瀏覽器指標
> |
Nokia 7110> |
Ericsson R320> |
Ericsson R380> |
UP.Browser> |
CARD最大字節數> |
1397 字節> |
3000 字節> |
3800 字節> |
1492 字節> |
圖象最大字節數> |
1397 字節> |
3000 字節?> |
3800 字節?> |
1492 字節?> |
顯示行數> |
4 (含標題行)> |
5> |
7> |
視終端不同> S3568i:6> |
顯示列數> |
19> |
14> |
不知道> |
視終端不同> |
顯示寬度(象素)> |
95> |
101> |
304> |
視終端不同> |
顯示高度(象素)> |
45> |
52> |
98> |
視終端不同> |
象素比例> |
1:1.25> |
不知道> |
1:1.23> |
視終端不同> |
字體> |
無> |
Small, Bold, Emphasis, Strong> |
Small, Big, Bold, Italic, Emphasis, Strong> |
Small, Big, Bold> |
文字位置> |
沒有,強制居左> |
居左、居中、居右> |
居左、居中、居右、段落縮進> |
不知道> |
圖象位置> |
強制居左> |
不知道> |
不知道> |
不知道> |
表格支持> |
不支持> |
最多5x5格> |
不知道> |
不知道> |
觸摸屏> |
無> |
無> |
有> |
無> |
圖標鍵> |
無> |
無> |
有> |
不知道> |
在WML頁面內撥號> |
"提取號碼" 功能> |
通過WTAI支持> |
通過WTAI支持> |
3.1以上版本的瀏覽器支持> |
輸入> |
在行內輸入> |
在設置位置輸入> |
在設置位置輸入> |
不知道> |
輸入格式> |
只有大小寫> |
不知道> |
不知道> |
不知道> |
圖形鏈接> |
無> |
有> |
有> |
不知道> |
鏈接格式> |
在行內> |
在設置位置> |
在設置位置> |
不知道> |
DECK下載順序> |
文字,然後圖形,再開始選擇性計時> |
文字,開始選擇性計時,然後是圖(結果有可能是CARD還未下載完畢就已過時)> |
不知道> |
> |
HTTP Redirect> |
支持> |
支持> |
支持> |
支持> |
沒有結構和進程就沒有程序。在WML中定義進程有很多方法,最簡單的就是任務。
WAP1.1定義了幾種類型的任務,任務通過對事件的響應改變程序的運行順序。有四種WML任務:· <noop>
· <prev>
· <refresh>
· <go>
<noop>
這個任務不做任何事情,一般用於屏蔽DECK級事件,語法非常簡單:
<noop/> |
<prev>
當用戶激活該任務時,終端就轉回上次用戶訪問過的URL。語法如下:
<prev> |
如果<prev>中包含了<setvar>元素,就會優先處理。
下面例子定義了一個只有Back按鈕的的DECK,按下以後會返回前面看過頁面。
<?xml version="1.0"?> |
<refresh>
當用戶激活該任務時,就執行一個刷新過程。如果這個任務裏使用<setvar>定義了變量,變量值將被重新設置。語法如下:
<prev> |
如果當前CARD含有<timer>元素,那麼在刷新時<timer>優先啓動。
下面的例子定義在屏幕刷新時重設firstname、lastname和age變量。
<do type="refresh"> |
<go>
當用戶激活該任務時,就引導用戶去WML中指定URL,可以是服務器上其他的DECK,也可以是本DECK中其他的CARD。語法如下:
<go |
href:必選屬性,指向一個合法URL。如果是其他的DECK,則該DECK的第一個CARD會顯示出來。如果是本DECK中的其他CARD,而歷史堆棧裏保存的是最新數據的話,則堆棧保持不變,直接調入該CARD。
sendreferer:如果爲true,用戶主體信息(USER AGENT)必須傳送給WAP網關。傳送時使用HTTP的提交頭信息,即儘可能簡短的相對URL。這個屬性可以用來給服務器控制存取URL的權力。默認值爲false。
Method:值必須爲get或post。分別用來產生HTTP的GET和POST請求。若爲get,則在URL中列出參數,例如:“http://www.wap86.net/bob.cgi?argone=one”;若爲post,則數據在請求內部傳送,不需要在URL中列出。
Accept-charset:指定字符集名稱列表,服務器在接受<go>的時候必須接受這個編碼規則。默認值爲unknown。具體內容這裏不作解釋,在以後的高級教程中描述。
下面是一個簡單的例子:
<go href="../topic.wml" sendreferer="true"> |
<postfield>
<postfield>並不是一個任務,但是跟<go>任務有關,所以在這裏介紹。它用來定義“名稱/值”對以便通過<go>向服務器發送HTTP請求。語法如下:
當用戶激活該任務時,就引導用戶去WML中指定URL,可以是服務器上其他的DECK,也可以是本DECK中其他的CARD。語法如下:
下面是一個簡單的例子:
<postfield name="STRING" value="STRING" /> |
當一個含有<postfield>的任務被執行的時候,終端要完成這樣一個過程:
1、識別“名稱/值”對並準備參數變量;
2、參數變量轉換成正確的字符集;
3、根據URL的ESCAPE規則對參數進行ESCAPE轉碼,編譯成application/x-www-form-urlencoded的MIME類型;
4、根據method指定的請求模式提交任務。
下面的例子演示get模式的用法:
<go href="../news.asp" sendreferer="true" method="get"> |
服務器將收到這樣的get請求:
GET ../news.asp?newstype=technology&newstext=wml HTTP/1.1 |
如果把前面的請求模式改成post,則同樣的<go>任務產生的這樣的post請求:
POST../news.asp HTTP/1.1 |
任務必須綁定倒某個事件上才能做一些有用的事情。
事件發生--〉任務執行,這纔是完整的進程控制。
有4個元素可以幫助你完成事件對任務的綁定:<anchor>、<onevent>、<timer>和<do>。
<anchor> 鏈接
象HTML一樣,WML也可以定義到其他程序的鏈接。在HTML中,鏈接通常用下劃線和特殊顏色的方式表示跟其他內容的區別。在WAP終端上則沒有嚴格的規則說如何表示一個鏈接,一般採用反白的顯示方式。
<anchor>的語法如下:
<anchor |
title:鏈接的標題;
xml:lang:語言編碼。
在這種定義方式中,實際上鍊接一般是通過<anchor>中包括的<go>元素完成的。比如下面的例子定義了2個CARD,點擊第一個CARD裏的“click me”鏈接會跳轉到第2個CARD:
<?xml version="1.0"?> |
點擊前顯示: |
點擊後顯示: |
||
|
|
鏈接還有一種短格式,語法如下:
<a |
除了跟原來一樣的兩個屬性以外,多了href屬性,可以對它直接指定URL。例如下面的例子定義了一個帶有圖像的鏈接:
<a title="HotBars" href="wap.hucn.com/HotBars.wml"> |
除了跟原來一樣的兩個屬性以外,多了href屬性,可以對它直接指定URL。
<onevent> 固有事件
WML定義了4種由用戶終端觸發的固有事件:
oneventforward:當用戶被<go>任務或其他機制(如一個SCRIPT過程)引導到一個CARD時觸發;
oneventbackward:當用回被<prev>或其他機制(如在設備上按BACK按鈕)引導到一個CARD時觸發;
ontimer:當TIMER計時結束時觸發。定義TIMER計時器可以使用<timer>元素,見下一節;
onpick:當用戶按下一個<option>選項時觸發(可以是選中或取消選擇)。
把這些事件綁定到一個任務要使用<onevent>元素,它的語法如下:
<onevent |
下面的例子演示瞭如何使用固有事件在CARD調入時清空變量。
<?xml version="1.0"?> |
<timer> 計時器
看名字就知道,這是個計時器,它在經過規定的計時時間以後產生一個任務。<timer>計時器只在所屬CARD裏有效:當進入CARD時,計時器開始工作;時間一到,觸發任務;如果離開CARD,計時器停止。語法如下:
<timer |
name:可選。指定一個包含計時時間的變量,在計時器開始工作以後,變量的值會逐漸減少。如果這個變量在<timer>之前就已經存在並且賦值爲一個非負整數,那後面value屬性的值會被忽略,直接使用變量裏的值作爲計時時限。
value:必選。指定計時時間,以1/10秒爲單位。
下面的例子每隔1秒顯示不同的文字(當然,你有興趣改成圖像也可以)。
<?xml version="1.0" standalone="yes"?> <card id = "card2" title = "card2"> <card id = "card3" title = "card3"> </wml> |
顯示結果如下,注意會不斷循環。 |
|
Sport選擇: |
|||
第1秒 |
第2秒 |
第3秒 |
|||
|
|
|
還有一個例子,通常用來做網站封面,顯示一段歡迎詞以後進入正式內容。這裏沒有使用圖片,各位可以自己加上試試看。
<?xml version="1.0"?> |
部件 |
功能 |
accept |
確認,接受輸入 |
prev |
退回歷史頁面訪問堆棧裏上一個CARD |
help |
上下文關聯的幫助信息 |
reset |
重設設備狀態 |
options |
上下文關聯的選項或附加操作 |
delete |
刪除當前內容或選擇 |
unknown |
由開發者自己定義 |
<do> 用戶觸發事件
每個WAP終端都預定義了一系列用戶界面部件,如手機上的按鈕、觸摸屏上的圖表、聲音指令或者其他一些很容易是別的部件。WML1.1定義了右面那些WAP兼容終端必須支持的部件。但是要說明的是,只有prev有預先定義的功能,其他的只是概念上的定義,需要根據開發者激活並賦予一定的動作。
當用戶激活這些部件的時候會產生相應的事件。你可以使用<do>元素捕獲這些事件並對其做出反應。下面是<do>的語法:
<do |
type:必選屬性,內容只能是那7種;
label:用戶接口部件的顯示標籤。如果終端不能顯示則被忽略。WML1.1建議此屬性長度限制在6個英文字符以內;
name:標誌“事件/任務”綁定關係的唯一名稱(在CARD範圍內)。CARD級的<do>事件替換同名的DECK級<do>事件(見下一節)。如果不指定name屬性或name爲空字符串,則name默認爲type的類型;
optional:告訴終端此軟按鈕在屏幕中是否顯示。如果此值設爲true,則忽略本<do>元素。默認值爲false;
xml:lang任務:語言代碼。
跟其他“事件/任務”綁定關係一樣,<do>裏的任務定義必須是<go>、<noop>、<prev>或<refresh>中的一個。
下面例子演示了<do>的使用方法。用戶按了不同的按鈕會被導向不同的CARD。
<?xml version="1.0"?> |
顯示結果 |
|||||
主畫面: |
按下“Links”按鈕以後: |
按下“Help”按鈕以後: |
|||
|
|
|
DECK級事件
前面已經講過可以用<template>元素定義DECK級事件,做法跟CARD級事件一樣,只要在<template>元素裏包含<do>或<onevent>事件就可以。這種做法可以定義一些在每個CARD裏都需要定義的事件,而不需要重複說明。
比如下面的例子給所有的CARD定義了BACK按鈕以便返回上一頁:
<?xml version="1.0"?> |