大家應該對這兩個詞很熟悉了,但是對詞里包含的意義可能并不是特別清楚。首先必須說明的是,程序員和系統分析員不存在誰高級誰低級的分別,他們是兩種職業,對職業技能的要求完全不同。所以厲害的程序員就是系統分析員的說法是不對的。當然,系統分析員的技能要求他必須要懂得如何寫程序,但是他的重心在于如何把一個很大的項目切割成適合個人的小塊,然后將這些小塊組織起來。程序員的職責就是如何更好更快的實現這些小塊。
在這章之前,我們討論的都是一個合格的程序員應當具備的技能,當然不止那一些內容。之所以在這里插進來討論系統分析員的事情,是因為我們的欄目叫做軟件工程而不是程序員從入門到精通之類的。
在正式開始之前,我們還是來看在Thinking In Java中作者對分析和設計的一段精辟見解:
分析和設計
面向對象的范式是思考程序設計時一種新的、而且全然不同的方式,許多人最開始都會在如何構造一個項目上皺起了眉頭。事實上,我們可以作出一個“好”的設計,它能充分利用OOP提供的所有優點。
請原諒在這里突然出現了OOP這個詞,他的意思是面相對象,雖然在之前沒有提到,但是在現在OO概念滿天飛的軟件世界里,大家應該對他不會太陌生。這里我簡要的說明一下。在之前我介紹的實際上都是在很早以前程序寫作流傳下來的經驗(什么,教我們老古董,打他!),但是以前的非OO(就是基于過程)的軟件設計方法目前在國際上已經很少采用,所以我這里講軟件設計的時候所有的概念都是基于OO的。即使OO的概念很簡單的啦,大家思考一下,我們再學習C++的時候一開始使用的類不都是一些動物啦、正方形啦之類的,都是生活中的例子,對吧。其實OO就是我們看世界的一種方式。可是最早由于計算機技術的不發達,我們不得不用一些很奇怪的描述來表達我們的意思,只有這樣計算機才能理解,很笨不是嗎。比如我們必須使用參數、過程、函數。所以當時的軟件設計方法都是基于過程的。舉一個簡單的例子來顯示OO設計方法和基于過程的設計方法之間的差別:一句簡單的日常短語--“我吃飯”,用OO的方法來表述還是“我吃飯”,可是如果用基于過程的方法來描述的話就變成“我吃飯(飯)”,是不是很別扭呢。如果大家覺得對于OO的方法還有什么問題的話,可以去看一下軟件工程專欄下的另一篇專題:《Thinking In Java賞析》
有關OOP分析與設計的書籍大多數都不盡如人意。其中的大多數書都充斥著莫名其妙的話語、笨拙的筆調以及許多聽起來似乎很重要的聲明。我認為這種書最好壓縮到一章左右的空間,至多寫成一本非常薄的書。具有諷剌意味的是,那些特別專注于復雜事物管理的人往往在寫一些淺顯、明白的書上面大費周章!如果不能說得簡單和直接,一定沒多少人喜歡看這方面的內容。畢竟,OOP的全部宗旨就是讓軟件開發的過程變得更加容易。盡管這可能影響了那些喜歡解決復雜問題的人的生計,但為什么不從一開始就把事情弄得簡單些呢?因此,希望我能從開始就為大家打下一個良好的基礎,盡可能用幾個段落來說清楚分析與設計的問題。
不要迷失
在整個開發過程中,最重要的事情就是:不要將自己迷失!但事實上這種事情很容易發生。大多數方法都設計用來解決最大范圍內的問題。當然,也存在一些特別困難的項目,需要作者付出更為艱辛的努力,或者付出更大的代價。但是,大多數項目都是比較“常規”的,所以一般都能作出成功的分析與設計,而且只需用到推薦的一小部分方法。但無論多么有限,某些形式的處理總是有益的,這可使整個項目的開發更加容易,總比直接了當開始編碼好!
也就是說,假如你正在考察一種特殊的方法,其中包含了大量細節,并推薦了許多步驟和文檔,那么仍然很難正確判斷自己該在何時停止。時刻提醒自己注意以下幾個問題:
(1) 對象是什么?(怎樣將自己的項目分割成一系列單獨的組件?)
(2) 它們的接口是什么?(需要將什么消息發給每一個對象?)
在確定了對象和它們的接口后,便可著手編寫一個程序。出于對多方面原因的考慮,可能還需要比這更多的說明及文檔,但要求掌握的資料絕對不能比這還少。
整個過程可劃分為四個階段,階段0剛剛開始采用某些形式的結構。
階段0:擬出一個計劃
第一步是決定在后面的過程中采取哪些步驟。這聽起來似乎很簡單(事實上,我們這兒說的一切都似乎很簡單),但很常見的一種情況是:有些人甚至沒有進入階段1,便忙忙慌慌地開始編寫代碼。如果你的計劃本來就是“直接開始開始編碼”,那樣做當然也無可非議(若對自己要解決的問題已有很透徹的理解,便可考慮那樣做)。但最低程度也應同意自己該有個計劃。
在這個階段,可能要決定一些必要的附加處理結構。但非常不幸,有些程序員寫程序時喜歡隨心所欲,他們認為“該完成的時候自然會完成”。這樣做剛開始可能不會有什么問題,但我覺得假如能在整個過程中設置幾個標志,或者“路標”,將更有益于你集中注意力。這恐怕比單純地為了“完成工作”而工作好得多。至少,在達到了一個又一個的目標,經過了一個接一個的路標以后,可對自己的進度有清晰的把握,干勁也會相應地提高,不會產生“路遙漫漫無期”的感覺。
從我剛開始學習故事結構起(我想有一天能寫本小說出來),就一直堅持這種做法,感覺就象簡單地讓文字“流”到紙上。在我寫與計算機有關的東西時,發現結構要比小說簡單得多,所以不需要考慮太多這方面的問題。但我仍然制訂了整個寫作的結構,使自己對要寫什么做到心中有數。因此,即使你的計劃就是直接開始寫程序,仍然需要經歷以下的階段,同時向自己提出一些特定的問題。
階段1:要制作什么?
在上一代程序設計中(即“過程化或程序化設計”),這個階段稱為“建立需求分析和系統規格”。當然,那些操作今天已經不再需要了,或者至少改換了形式。大量令人頭痛的文檔資料已成為歷史。但當時的初衷是好的。需求分析的意思是“建立一系列規則,根據它判斷任務什么時候完成,以及客戶怎樣才能滿意”。系統規格則表示“這里是一些具體的說明,讓你知道程序需要做什么(而不是怎樣做)才能滿足要求”。需求分析實際就是你和客戶之間的一份合約(即使客戶就在本公司內部工作,或者是其他對象及系統)。系統規格是對所面臨問題的最高級別的一種揭示,我們依據它判斷任務是否完成,以及需要花多長的時間。由于這些都需要取得參與者的一致同意,所以我建議盡可能地簡化它們——最好采用列表和基本圖表的形式——以節省時間。可能還會面臨另一些限制,需要把它們擴充成為更大的文檔。
我們特別要注意將重點放在這一階段的核心問題上,不要糾纏于細枝末節。這個核心問題就是:決定采用什么系統。對這個問題,最有價值的工具就是一個名為“使用條件”的集合。對那些采用“假如……,系統該怎樣做?”形式的問題,這便是最有說服力的回答。例如,“假如客戶需要提取一張現金支票,但當時又沒有這么多的現金儲備,那么自動取款機該怎樣反應?”對這個問題,“使用條件”可以指示自動取款機在那種“條件”下的正確操作。
應盡可能總結出自己系統的一套完整的“使用條件”或者“應用場合”。一旦完成這個工作,就相當于摸清了想讓系統完成的核心任務。由于將重點放在“使用條件”上,一個很好的效果就是它們總能讓你放精力放在最關鍵的東西上,并防止自己分心于對完成任務關系不大的其他事情上面。也就是說,只要掌握了一套完整的“使用條件”,就可以對自己的系統作出清晰的描述,并轉移到下一個階段。在這一階段,也有可能無法完全掌握系統日后的各種應用場合,但這也沒有關系。只要肯花時間,所有問題都會自然而然暴露出來。不要過份在意系統規格的“完美”,否則也容易產生挫敗感和焦燥情緒。
在這一階段,最好用幾個簡單的段落對自己的系統作出描述,然后圍繞它們再進行擴充,添加一些“名詞”和“動詞”。“名詞”自然成為對象,而“動詞”自然成為要整合到對象接口中的“方法”。只要親自試著做一做,就會發現這是多么有用的一個工具;有些時候,它能幫助你完成絕大多數的工作。
盡管仍處在初級階段,但這時的一些日程安排也可能會非常管用。我們現在對自己要構建的東西應該有了一個較全面的認識,所以可能已經感覺到了它大概會花多長的時間來完成。此時要考慮多方面的因素:如果估計出一個較長的日程,那么公司也許決定不再繼續下去;或者一名主管已經估算出了這個項目要花多長的時間,并會試著影響你的估計。但無論如何,最好從一開始就草擬出一份“誠實”的時間表,以后再進行一些暫時難以作出的決策。目前有許多技術可幫助我們計算出準確的日程安排(就象那些預測股票市場起落的技術),但通常最好的方法還是依賴自己的經驗和直覺(不要忘記,直覺也要建立在經驗上)。感覺一下大概需要花多長的時間,然后將這個時間加倍,再加上10%。你的感覺可能是正確的;“也許”能在那個時間里完成。但“加倍”使那個時間更加充裕,“10%”的時間則用于進行最后的推敲和深化。但同時也要對此向上級主管作出適當的解釋,無論對方有什么抱怨和修改,只要明確地告訴他們:這樣的一個日程安排,只是我的一個估計!
階段2:如何構建?
在這一階段,必須拿出一套設計方案,并解釋其中包含的各類對象在外觀上是什么樣子,以及相互間是如何溝通的。此時可考慮采用一種特殊的圖表工具:“統一建模語言”(UML)。請到http://www.rational.com去下載一份UML規格書。作為第1階段中的描述工具,UML也是很有幫助的。此外,還可用它在第2階段中處理一些圖表(如流程圖)。當然并非一定要使用UML,但它對你會很有幫助,特別是在希望描繪一張詳盡的圖表,讓許多人在一起研究的時候。除UML外,還可選擇對對象以及它們的接口進行文字化描述(就象我在《Thinking in C++》里說的那樣,但這種方法非常原始,發揮的作用亦較有限。
我曾有一次非常成功的咨詢經歷,那時涉及到一小組人的初始設計。他們以前還沒有構建過OOP(面向對象程序設計)項目,將對象畫在白板上面。我們談到各對象相互間該如何溝通(通信),并刪除了其中的一部分,以及替換了另一部分對象。這個小組(他們知道這個項目的目的是什么)實際上已經制訂出了設計方案;他們自己“擁有”了設計,而不是讓設計自然而然地顯露出來。我在那里做的事情就是對設計進行指導,提出一些適當的問題,嘗試作出一些假設,并從小組中得到反饋,以便修改那些假設。這個過程中最美妙的事情就是整個小組并不是通過學習一些抽象的例子來進行面向對象的設計,而是通過實踐一個真正的設計來掌握OOP的竅門,而那個設計正是他們當時手上的工作!
作出了對對象以及它們的接口的說明后,就完成了第2階段的工作。當然,這些工作可能并不完全。有些工作可能要等到進入階段3才能得知。但這已經足夠了。我們真正需要關心的是最終找出所有的對象。能早些發現當然好,但OOP提供了足夠完美的結構,以后再找出它們也不遲。
階段3:開始創建
讀這本書的可能是程序員,現在進入的正是你可能最感興趣的階段。由于手頭上有一個計劃——無論它有多么簡要,而且在正式編碼前掌握了正確的設計結構,所以會發現接下去的工作比一開始就埋頭寫程序要簡單得多。而這正是我們想達到的目的。讓代碼做到我們想做的事情,這是所有程序項目最終的目標。但切不要急功冒進,否則只有得不償失。根據我的經驗,最后先拿出一套較為全面的方案,使其盡可能設想周全,能滿足盡可能多的要求。給我的感覺,編程更象一門藝術,不能只是作為技術活來看待。所有付出最終都會得到回報。作為真正的程序員,這并非可有可無的一種素質。全面的思考、周密的準備、良好的構造不僅使程序更易構建與調試,也使其更易理解和維護,而那正是一套軟件贏利的必要條件。
構建好系統,并令其運行起來后,必須進行實際檢驗,以前做的那些需求分析和系統規格便可派上用場了。全面地考察自己的程序,確定提出的所有要求均已滿足。現在一切似乎都該結束了?是嗎?
階段4:校訂
事實上,整個開發周期還沒有結束,現在進入的是傳統意義上稱為“維護”的一個階段。“維護”是一個比較曖昧的稱呼,可用它表示從“保持它按設想的軌道運行”、“加入客戶從前忘了聲明的功能”或者更傳統的“除掉暴露出來的一切臭蟲”等等意思。所以大家對“維護”這個詞產生了許多誤解,有的人認為:凡是需要“維護”的東西,必定不是好的,或者是有缺陷的!因為這個詞說明你實際構建的是一個非常“原始”的程序,以后需要頻繁地作出改動、添加新的代碼或者防止它的落后、退化等。因此,我們需要用一個更合理的詞語來稱呼以后需要繼續的工作。
這個詞便是“校訂”。換言之,“你第一次做的東西并不完善,所以需為自己留下一個深入學習、認知的空間,再回過頭去作一些改變”。對于要解決的問題,隨著對它的學習和了解愈加深入,可能需要作出大量改動。進行這些工作的一個動力是隨著不斷的改革優化,終于能夠從自己的努力中得到回報,無論這需要經歷一個較短還是較長的時期。
什么時候才叫“達到理想的狀態”呢?這并不僅僅意味著程序必須按要求的那樣工作,并能適應各種指定的“使用條件”,它也意味著代碼的內部結構應當盡善盡美。至少,我們應能感覺出整個結構都能良好地協調運作。沒有笨拙的語法,沒有臃腫的對象,也沒有一些華而不實的東西。除此以外,必須保證程序結構有很強的生命力。由于多方面的原因,以后對程序的改動是必不可少。但必須確定改動能夠方便和清楚地進行。這里沒有花巧可言。不僅需要理解自己構建的是什么,也要理解程序如何不斷地進化。幸運的是,面向對象的程序設計語言特別適合進行這類連續作出的修改——由對象建立起來的邊界可有效保證結構的整體性,并能防范對無關對象進行的無謂干擾、破壞。也可以對自己的程序作一些看似激烈的大變動,同時不會破壞程序的整體性,不會波及到其他代碼。事實上,對“校訂”的支持是OOP非常重要的一個特點。
通過校訂,可創建出至少接近自己設想的東西。然后從整體上觀察自己的作品,把它與自己的要求比較,看看還短缺什么。然后就可以從容地回過頭去,對程序中不恰當的部分進行重新設計和重新實現(注釋⑩)。在最終得到一套恰當的方案之前,可能需要解決一些不能回避的問題,或者至少解決問題的一個方面。而且一般要多“校訂”幾次才行。
構建一套系統時,“校訂”幾乎是不可避免的。我們需要不斷地對比自己的需求,了解系統是否自己實際所需要的。有時只有實際看到系統,才能意識到自己需要解決一個不同的問題。若認為這種形式的校訂必然會發生,那么最好盡快拿出自己的第一個版本,檢查它是否自己希望的,使自己的思想不斷趨向成熟。
反復的“校訂”同“遞增開發”有關密不可分的關系。遞增開發意味著先從系統的核心入手,將其作為一個框架實現,以后要在這個框架的基礎上逐漸建立起系統剩余的部分。隨后,將準備提供的各種功能(特性)一個接一個地加入其中。這里最考驗技巧的是架設起一個能方便擴充所有目標特性的一個框架(對這個問題,大家可參考第16章的論述)。這樣做的好處在于一旦令核心框架運作起來,要加入的每一項特性就象它自身內的一個小項目,而非大項目的一部分。此外,開發或維護階段合成的新特性可以更方便地加入。OOP之所以提供了對遞增開發的支持,是由于假如程序設計得好,每一次遞增都可以成為完善的對象或者對象組。
⑩:這有點類似“快速造型”。此時應著眼于建立一個簡單、明了的版本,使自己能對系統有個清楚的把握。再把這個原型扔掉,并正式地構建一個。快速造型最麻煩的一種情況就是人們不將原型扔掉,而是直接在它的基礎上建造。如果再加上程序化設計中“結構”的缺乏,就會導致一個混亂的系統,致使維護成本增加。
計劃的回報
如果沒有仔細擬定的設計圖,當然不可能建起一所房子。如建立的是一所狗舍,盡管設計圖可以不必那么詳盡,但仍然需要一些草圖,以做到心中有數。軟件開發則完全不同,它的“設計圖”(計劃)必須詳盡而完備。在很長的一段時間里,人們在他們的開發過程中并沒有太多的結構,但那些大型項目很容易就會遭致失敗。通過不斷的摸索,人們掌握了數量眾多的結構和詳細資料。但它們的使用卻使人提心吊膽在意——似乎需要把自己的大多數時間花在編寫文檔上,而沒有多少時間來編程(經常如此)。我希望這里為大家講述的一切能提供一條折衷的道路。需要采取一種最適合自己需要(以及習慣)的方法。不管制訂出的計劃有多么小,但與完全沒有計劃相比,一些形式的計劃會極大改善你的項目。請記住:根據估計,沒有計劃的50%以上的項目都會失敗!
非常佩服作者對軟件構建過程的精辟見解,軟件工程是一門內容非常繁雜的學科,但是作者能夠用淺顯易懂的句子把它描述出來,真的是非常不簡單。軟件工程最早的提出者并不是計算機的專業人士,而是一位建筑設計師,所以軟件工程的很多思想來自于建筑學。經過了幾十年的發展,軟件工程經歷了很多次的蛻變。形成了今天的世界上以一些大公司提出的架構為主的形式:比如微軟提出的COM及COM+以及基于其上的DNA體系,SUN提出的EJB,CORBA,還有BEA、WebLogic、IBM等公司的架構。雖然架構有不同,但是他們的思想都是相通的,架構的作用都是起到輔助開發者實現規范的、科學的軟件開發過程。至于談軟件項目的管理和開發,那么Rational公司就是這方面的鼻祖。綜合來說,目前世界范圍內的軟件工程提倡的就是以漸進的、螺旋式的開發方法構建基于組件的軟件產品。現在說這些東西可能有些畫餅的嫌疑,隨著我們專題討論的繼續深入,這些概念就會很清晰的展現在面前。
雖然很希望能夠繼續的討論軟件工程方面的東東,但是我們的這個專題畢竟是討論如何編寫優美的程序的,離題還是不要太過分的好,至于軟件工程的詳細討論,我會在接下去的專題中繼續。在接下去的篇幅中,我們會繼續討論程序員和系統分析員之間的差別。
posted @
2006-04-29 19:46 崛起的程序員 閱讀(226) |
評論 (0) |
編輯 收藏
【 原 文 由 驕 傲 的 中 國 人 所 發 表 】
就 象 ken_qian 所 說 的 , “ 出 了國門,大家都在變。”短短半年間,自己確實在觀念上改變了許多。回想起來,以前在國內自己只是一部不停運作的編程機器,整天寫code,寫code,寫code,寫code!一旦靈感一來,就想方設法地把所想的寫出來,根本就沒有考慮到編程以外的事情,結果,光是寫出來的soucecode足用十幾M,真是寫得昏天黑地,日月無光!!:)可是,到了硅谷,情形突變!自以為能在鬼老面前,炫耀一下編程的能耐,好讓他們對中國人刮目相看。可惜我錯了!他們根本就不屑一顧!上的課多了,與不少在世界聞名的大電腦公司任職的教授也交談過,發現自己是多么的無知,多么的膚淺。:(在上projectmanagement課時,已經明顯體現出觀念的差別。在上client/serveroverview時,更加突出了,整本教材(在這里這本書是專業人員必讀的)沒有一行code,幾乎涵蓋了現在所有流行的先進client/server(2/3-tiers)技術。從軟件的角度分析它們的起源,發展和前途,還有各種功能相似技術的對比。整本書貫穿著一種思想,它與國內被絕大多數人奉行為至理名言的一句話-"不管黑貓白貓,只要抓到老鼠就是好貓!"--截然相反:“即使能抓到老鼠的黑貓白貓,也不一定是好貓!”。而這堂課的project就是做一個3-tierclient/server的項目,不用寫code,只是要詳細寫出用到的結構和技術,為什么要用這而不用那?其實就是讓你對各種相近技術進行詳細比較,清楚地認識各種技術的優劣!!
短短半年研究生學習,與本科時確實是天壤之別。人家認為本科只是寫code的時期,給出一個項目,只要能完成就算成功了。而到了研究生階段,就要學會分析比較,對所用技術一定要能說出個道理:“在眾多技術中,為什么你要選擇這個?”還要經得起別人的“窮追猛打”。舉個例子:抓到老鼠的黑貓白貓,白的一天能抓10只老鼠,而黑的只能抓5只,但是白的飯量很大,是黑的兩倍。黑的比白的要便宜一倍。。。那么到底誰是好貓呢??:)
象vcc所說的“程序員最重要的是思維能力,只有想不出,沒有編不出”。在如今,internet流行,和控件泛濫的年代,對于大多數程序已經不是能不能寫出來的問題了。我不是什么絕頂高手,也不是一個博學多才的人,有許多編程的問題還是不懂,但狂妄的說一句,現在只要能給我鉆研上幾天,長的幾周,就沒有什么不能編不出來的。可惜這有什么用呢,充其量只是一部編程機器。
只會給人牽著走,整天做牛做馬。這里培養的是具有大局觀的人才,編程水平可能不高,但是活躍的思維,管理的能力和高瞻遠矚的眼界是我自愧不如的。就象BILLGATES當年若沒有超凡的管理頭腦,他現在可能也只是一部頂級的編程機器。
對于中國,以前沒有internet,資料奇缺。我以前學C++的時候,周圍的人還不知道是什么玩意!靠的就是ONLINEHELP和以后的MSDN,想問別人,也沒人懂!就象我在簽名檔所寫的“孤身走我路...”。如今,internet的流行,我認為技術已經不是一個主要問題了,不懂的,上網查詢,問人,什么最新的資料,sourcecode,控件應有盡有,還怕寫不出來?!作為過來人,我只是想努力地把硅谷的一丁點文化,一丁點精神帶給國內的同行。君不見,我所發表的每一長篇“大論”,全都是從大局出發,從觀念出發,很少涉及到具體的編程代碼。我也是中國人,我深知在“有中國特色”的制度下,硅谷的文化和精神是很難實現的。但是我總認為,雖然不能在現實社會中實現,但是可以在網上,在這虛擬的世界中營造一種氣氛,使大伙能體會一下這種感覺。學C的畢竟是編程的正宗,有不少高手,而且是中國計算機業的中流砥柱。所以我選擇了C版作為開始。可惜我錯了,大家也許受現實工作生活的壓力,在網上也不能夠擺脫。就如我當年一樣,“只是一部不停運作的編程機器”。你們總是抱怨現實的中國怎樣怎樣,個人如何如何渺小。可是到了網上,到了這個自由的天地,根本沒有什么污腐制度的束縛,什么文憑證書的限制,完全可以靠大伙每個人的力量來實現,卻不見有什么實際的行動。哈哈,怨天尤人有什么用,根本就不從自身找找原因,那么即使是給你一個很好的環境,一個很好的制度,結果又是怎樣呢??我不希望這就是中國人的劣性,若是這樣,我也無話可說了。
寫完這遍文章,我也累了。也許,不!應該是肯定會招來不少人的反感,你們也許不屑一顧,也許破口大罵。不過我真的累了!!個人力量的確很渺小,要改變中國人的固有觀念,的確不是我力所能及的。況且我本身也有許多不足。也許就象國歌所唱的:“中華民族到了最危險的時候”,每個人才被迫“發出最后的吼聲,起來,起來,起來!!。。。”最后,還是象我在簽名檔所寫的:“孤身走我路...”
Goodnight,everybody!
/Crazyjava
孤身走我路...
其實,路,兩個人一起走比一個人要好。
posted @
2006-04-29 19:37 崛起的程序員 閱讀(171) |
評論 (0) |
編輯 收藏
我們都知道JAVA是一種解析型語言,這就決定JAVA文件編譯后不是機器碼,而是一個字節碼文件,也就是CLASS文件。而這樣的文件是存在規律的,經過反編譯工具是可以還原回來的。例如Decafe、FrontEnd,YingJAD和Jode等等軟件。下面是《Nokia中Short數組轉換算法》
thread.jspa?threadID=872&tstart=0
類中Main函數的ByteCode:
0?ldc?#16?
2?invokestatic?#18?
5?astore_1
6?return
其源代碼是:short?[]?pixels?=?parseImage(\"/ef1s.png\");
我們通過反編譯工具是可以還原出以上源代碼的。而通過簡單的分析,我們也能自己寫出源代碼的。
第一行:ldc?#16?
ldc為虛擬機的指令,作用是:壓入常量池的項,形式如下
ldc?index
這個index就是上面的16,也就是在常量池中的有效索引,當我們去看常量池的時候,我們就會找到index為16的值為String_info,里面存了/ef1s.png.
所以這行的意思就是把/ef1s.pn作為一個String存在常量池中,其有效索引為16。
第二行:2?invokestatic?#18?
invokestatic為虛擬機指令,作用是:調用類(static)方法,形式如下
invokestatic?indexbyte1?indexbyte2
其中indexbyte1和indexbyte2必須是在常量池中的有效索引,而是指向的類型必須有Methodref標記,對類名,方法名和方法的描述符的引用。
所以當我們看常量池中索引為18的地方,我們就會得到以下信息:
Class?Name?:?cp_info#1?
Name?Type?:?cp_info#19?
1?和19都是常量池中的有效索引,值就是右邊<>中的值,再往下跟蹤我就不多說了,有興趣的朋友可以去JAVA虛擬機規范。
這里我簡單介紹一下parseImage(Ljava/lang/String;)[S?的意思。
這就是parseImage這個函數的運行,我們反過來看看parseImage的原型就明白了
short?[]?parseImage(String)
那么Ljava/lang/String;就是說需要傳入一個String對象,而為什么前面要有一個L呢,這是JAVA虛擬機用來表示這是一個Object。如果是基本類型,這里就不需要有L了。然后返回為short的一維數組,也就是對應的[S。是不是很有意思,S對應著Short類型,而“[”對應一維數組,那有些朋友要問了,兩維呢,那就“[[”,呵呵,是不是很有意思。
好了,調用了函數,返回的值要保存下來吧。那么就是第三行要做的事情了。
第三行:5?astore_1
呵呵,很簡單的。但是卻有文章,也是比較容易混亂的地方。
astore_為虛擬機指令,作用為:將當前reference存儲到局部變量中去。而必須是對當前框架的局部變量的有效索引。打個比方,可能我們這個函數中可能還要用到這個局部變量,我們可以通過來找到它。例如調用虛擬機指令:
aload_1,就能得到該值。
第四行:6?return
同樣的,return也是虛擬機指令了,它的作用為:從方法返回void。
這里也就是退出main函數。
----------------------------------------------------------------------------
ok,終于啰嗦完畢了。有些朋友可能要問,這么復雜,才四行就說這么多,呵呵,可能是我這人廢話過多,當然如果你熟悉了,一點就能看懂了。通過肉眼就可以反編譯程序了。目前所有的反編譯工具都無法做到完美反編譯,在有問題的地方還需要人去修正。
好了,說了半天如何反編譯,我們就來看看如果在你的程序如果防止別人來反編譯。好不容易寫好的程序被人反編譯了,多郁悶。哈哈。工欲善其事,必先利其器,這句話用對了嗎?
什么混淆等等的方法,我就不說了,我這里主要是要說一種通過添加代碼來在某種程度來避免當前流行的反編譯工具對你的代碼進行反編譯。
方案一。
1,首先要添加一個參數為Exception類型的函數,例如這樣。
public?static?void?Fake(Exception?e)
{
e.toString();
}
一定要有e.toString();,因為要防止你的混淆器把無用的代碼過濾。
2,然后在每個類中調用這個函數,放在try...catch(Exception?e)..中的catch里面,例如:
try
{
...
}
catch?(Exception?e)
{
Fake(e);
}
請注意?,一定要放在catch才有用,其他地方無用。
方案二。
如果以上方法還不夠專業,我們再來一個。呵呵~
1,同樣的,我們定義一個類,這個類叫做AntiCrack.。名字好像有點大。。。代碼如下:
public?class?AntiCrack
{
private?AntiCrack()
{
}
public?static?Throwable?Fake(Throwable?throwable,?Throwable?throwable1)
{
try
{
throwable.getClass().getMethod(\"initCause\",?new?Class[]?{
java.lang.Throwable.class
}).invoke(throwable,?new?Object[]?{
throwable1
});
}
catch(Exception?exception)?{?}
return?throwable;
}
}
2,同樣的,我們在catch里面調用該函數。例如如下。
try
{
//your?code?here?
}
catch(IOException?ioexception)
{
IllegalArgumentException?illegalargumentexception?=?new?IllegalArgumentException(ioexception.toString());
AntiCrack.fake(illegalargumentexception,?ioexception);
throw?illegalargumentexception;
}
或者也可以這樣
public?class?AntiException?extends?Exception
{
public?AntiException()
{
}
public?AntiException(String?s)
{
super(s);
}
public?AntiException(String?s,?Throwable?throwable)
{
super(s);
AntiCrack.fake(this,?throwable);
}
}
然后在你的程序里面?
try
{
}
catch(IoException?e)
{
throw?new?AntiException(ioexception.toString(),?ioexception);
}
當采用以上方式后,任何類只要調用了該函數,生成的class反編譯后出錯,得不到結果。
Decafe、FrontEnd和YingJAD,反編譯時都有exception,然后無法進行下去。大家可以多測試變得反編譯工具。建議推薦用第二個方法。
posted @
2006-04-29 09:56 崛起的程序員 閱讀(963) |
評論 (0) |
編輯 收藏
WML?Script標準函數庫
這節會討論標準的WML?Script函數庫。
6.1?WML?Script規則
這些標準函數庫提供一個擴展WML?Script語言的機制,這些特定的函數庫必須遵循WML?Script的規則。
支持的數據格式
下面的WML?Script格式使用于程序的定義之中,這樣能記錄程序參數與回轉值的格式。
Boolean
Integer
Float
String
Invalid
除此之外,如果整數與浮點數參數值格式都能接受的話,則能使用number來記錄參數格式,如果使用的格式是所支持的格式,則能用any來記錄。
數據格式轉換
函數庫程序發生錯誤的處理方式和WML?Script語言一樣。
invalid程序參數會產生invalid的回傳值。
程序的參數無法轉成所需要使用參數格式,則會產生invalid的回傳值。
與程序相關的錯誤得出回傳一個適當的錯誤碼,至于這個值就要看每個程序如何定義。
6.2?Lang函數庫
名稱:Lang
說明:這個函數庫所含的程序同WML?Script語言的核心有很密切的關系。
abs
程序:abs(value)
說明:回傳給予數的絕對值。
如果給予的數是整數,則回傳整數。
如果給予的數是浮點數,則回傳浮點數。
參數:value=數字。
回傳值:數字或invalid。
例外狀況:var?a?=-3;
var?b?=Lang.abs(a);//b=3
min?
范例:var?a?=?-3
var?b?=?Lang.abs(a);?
var?c?=?Lang.min(a.b);
var?d?=?Lang.min(45、76.3);//d=45(ingteger)
var?e?=?Lang.min(45、76.3);//e=45(ingteger)
max
程序:max(value1,value2)
說明:回傳值給予的兩個數之間的較大值,回傳的值于格式同所選數值的值與格式相同,其選取的方式如下:
WML?Script運算符數據格式的整數與浮點數轉換法則可用來確認數據格式,以便執行比較的動作。
參數:value1?=數字
value2?=數字
回傳值:數字或invalid
例外狀況:無
范例:var?a?=-3;
var?b?=Lang.abs(a);//b=3
var?c?=?Lang.min(a.b);
var?d?=?Lang.min(45、76.3);//d=45(ingteger)
var?e?=?Lang.min(45、76.3);//e=45(float)
parseInt
程序:parseInt(value)
說明:回傳由字符串value所定義的整數值,合法的整數語法由WML?Script數值字符串文法或是近值整數是字所界定,下列為額外的解析法則:
第一個字符不是由+、-或十進制數字當開頭的話,解譯結束。
結果:解析過的字符串回轉換整數值。
范例:var?i?=Lang.parseInt(\"1234\");?//?i=1234
var?j?=Lang.parseInt(\"100?m/s\");?//?j=100
parseFloat
程序:parseFloat(value)
說明:回傳由字符串value所定義的浮點數值,合法的浮點數語法由WML?Script數值字符串文法或是近值整數實字所界定,下列為額外的解析法則:
第一個字符無法解析成浮點數表達式,解析結束。
結束:解析過的字符串回轉換成浮點數。
參數:value=字符串
回傳值:浮點數或invalid
例外狀況:解析錯誤則傳回invalid
范例:var?a?=Lang.parseFloat(\"123.7?Hz\");?//?a=123.7
var?b?=Lang.parseFloat(\"7.34e2?Hz\");?//?b=7.34e2
var?c?=Lang.parseFloat(\"70.0e-2?F\");?//?c=70.0e-2
var?d?=Lang.parseFloat(\"-1.c\");?//?d=0.1
var?e?=Lang.parseFloat(\"100\");?//?e=100.0
var?f?=Lang.parseFloat(\"Number:5.5\");?//?f=invalid
var?g?=Lang.parseFloat(\"7.3e?meters\");?//?g=invalid
var?h?=Lang.parseFloat(\"7.3e-?m/s\");?//?h=invalid
isInt
程序:isInt(value)
說明:如果各預的值value能使用parseInt(value)轉成整數則回傳布爾值ture,否則傳回false。
參數:value=任意值
回傳值:布爾值或invalid
例外狀況:無
范例:var?a=Lang.inInt(\"-123\");?//ture
var?a?=Lang.minInt(\"123.33\");?//ture
var?a?=Lang.minInt(\"string\");?//false
var?a?=Lang.minInt(\"#123\");?//false
var?a?=Lang.minInt(\"invalid\");?//invalid
isFloat
程序:isFloat(value)
說明:如果各預的值value能使用parseInt(value)轉成整數則回傳布爾值ture,否則傳回false。
參數:value=任意值
回傳值:布爾值或invalid
例外狀況:無
范例:var?a=Lang.inInt(\"-123\");?//ture
var?a?=Lang.minInt(\"123.33\");?//ture
var?a?=Lang.minInt(\"string\");?//false
var?a?=Lang.minInt(\"#123\");?//false
var?a?=Lang.minInt(\"invalid\");?//invalid
maxInt
程序:maxInt()
說明:傳回最大的整數值。
參數:無
回傳值:整數2147483647
例外狀況:無
范例:var?a?=Lang.minInt();
minInt
程序:minInt()
說明:傳回最小的整數值
參數:無
回傳值:整數-2147483647
例外狀況:無
范例:var?a?=Lang.minInt();
float
程序:float()
說明:如果有支持浮點數的話傳回ture,沒有的話傳回false。
參數:無
回傳值:布爾值
例外狀況:無
范例:var?floatsSupported?=?Lang.float();
exit
程序:exit(value)
說明:結束WML?Script位碼的解譯然后回到調用WML?Script解譯器者的控制,并回傳指定值value,你可以使用這個程序來執行由一般程序的結束,而且WML?Script位碼的執行必須停止。
參數:valre=任意值
回傳值:無,這個程序結束解譯
例外狀況:無
范例:Lang.exit(\"Value:\"?+?myVal);//Returns?a?string
Lang,exit(invalid);//?Returns?invalid
abort
程序:abort(errorDescription)
說明:中止WML?Script位碼的解譯然后回到調用WML?Script解譯器者的控制,并回傳?errorDescription,你能使用這個程序執行不正常的中止,調用程序者檢測到有嚴重錯誤,WML?Script的執行并須中斷。
如果errorDescription的格式為invalid,字符串invalid用代替errorDescription的使用。
參數:errorDescription?=字符串
回傳值:無,這個程序結束解譯
例外狀況:無
范例:Lang.abort(\"Error:\"?+?errVal);?//?Error?value?string
radndom
程序:random(value)
說明:回傳一個正數的整數值,也就是說要大于或等于零,但必須要小于給定值value,回傳值是由近是正常分布所隨機選取的值。
參數:value=整數
回傳值:整數或invalid
例外狀況:如果value等于0,則程序回傳0
如果value小于0,則程序回傳invalid
范例:var?a?=10;
var?b?=Lang.random(5.1)*a;//b=0..50
var?c?=?Lang.random(\"string\");?//?c=invalid
reed
程序:seed(alue)
說明:初始化需隨機數字順序并回傳一個空字符串
如果value為0或正整數,給予的value則用來初始化,反之則使用隨機初始化的值。
如果value為浮點數,則會先使用Float.int()來計算確切的整數值。
參數:value=整數
回傳值:字符串或invalid]
例外狀況:無
范例:var?a?=Lang.reed(123);//?a=\"\"
var?b?=Lang.random(20);?//?b=0..20
var?c?=?Lang.seed(\"seed\");?//?c=invalid?(random?seed?//left?unchanged)
characterSet
程序:characterSet()
說明:回傳WML?Script解譯器所支持的字集,回傳只是個整數用來記錄由IANA所設定的MIB?Enum值,這個只能表示所有的字集。
參數:無
回傳值:整數
例外狀況:無
范例:Var?charset?=?Lang.characterSet();?//charset?=?4?for?latinl
6.3?Float函數庫
名稱:Float
說明:這個函數庫包含了典型與常用的浮點數算術程序。
int
程序:int(value)
說明:回傳給予值的整數部分。
參數:value=數字
回傳值:整數或invalid
例外狀況:無
范例:var?a?=3.14;
var?b?=Float.in(a);?//b=3
var?c?=Float.in(-2.8);?//c=-2
floor
程序:floor(value)
說明:回傳整數值,這個只要最接近給予值但不能大于它。
如果value已經是個整數,其結果就是這個值本身。
參數:value=數字
回傳值:整數或invalid
例外狀況:無
范例:var?a?=3.14;
var?b?=Float.in(a);?//b=3
var?c?=Float.in(-2.8);?//c=-3
ceil
程序:ceil(value)
說明:回傳一個只要最接近給予值但不能小于它的整數值。
如果value已經是個整數,其結果就是這個值本身。
參數:value=數字
回傳值:整數或invalid
例外狀況:無
范例:var?a?=3.14;
var?b?=Float.in(a);?//b=4
var?c?=Float.in(-2.8);?//c=-2
pow
程序:pow(x,y)
說明:回傳x的y次方值。
如果x是負數,則y必須為正數。
參數:x=數字
?y=數字
回傳值:浮點數或invlid
例外狀況:如果x=?=0而且?y<0,則回傳invalid
如果x<0而且y不是個整數,則回傳invalid
范例:var?a?=3
var?b?=Float.pow(a,2);?//b=9
round
程序:round(value)
說明:傳回最接近給予值的整數
若兩個整數值跟value接近的程序相等,則選擇比較大的數。
若value已經是個正數,其結果就是value本身。
參數:value=數字
回傳值:整數或invalid
例外狀況:無
范例:var?a=Float.round(3.5);?//?a=4
var?b=Float.round(-3.5);?//b=-3
var?c=Float.round(0.5);?//?c=1
var?d=Float.round(-0.5);?//d=0
squt
程序:sqrt(value)
說明:傳回給予值value的平方根近似值。
參數:value=浮點數
回傳值:浮點數或invalid
例外狀況:如果value負數,則回傳invlid
范例:var?a=4;
var?b=Float.squt(a);?//b=2.0
var?c=Float.squt(5);?//c=2.2360679775
maxFloat
程序:maxFloat()
說明:傳回IEEE?754所支持的但準浮點數格式中最大的浮點數值。
參數:無
回傳值:浮點數3.40282347E+38
例外狀況:無
范例:var?a=Float.maxFloat();
minFloat
程序:minFloat()
說明:傳回IEEE?754所支持的但準浮點數格式中最小的浮點數值。
參數:無
回傳值:浮點數1.17549435E-38
例外狀況:無
范例:var?a=Float.minFloat();
6.4?string函數庫
名稱:字符串
說明:這個函數庫包含了字符串程序的集合,一個字符串可以是字符數組,每個字符都有個索引,字符串的第一個字浮的索引為0,字符串的長度是字符在數組中的數目。
你能使用一些特殊的分隔符號來界定不同的字符串,這樣你就能存取這些有分隔符號予元素索引所界定出的元素,字符串中第一個元素的索引值為0,每個字符串分隔符號回分隔出兩個元素,但字符是不能用來做分隔符號。
一個空格的字符可能是下列字符其中之一:
TAB:水平跳格定位(horizontal?tabulation)
VT:垂直跳格定位(ertival?tabulation)
FF:跳頁(from?feed)
SP:空格(space)
LF:跳行(line?feed)
CR:歸位(carriage?return)
length
程序:length(string)
說明:傳回給予字符串的長度(字符的數目)。
參數:string=字符串
回傳值:整數或invalid
例外狀況:無
范例:var?a=\"ABC\";
var?b=string.length(a);?//b=3
var?c=string.length(\"\");?//c=0
var?d=string.length(342);?//d=3
is?Empty
程序:is?Empty(string)
說明:如果字符串長度為零則傳回布爾值true,反之傳回false。
參數:string=字符串
回傳值:布爾值或invalid
例外狀況:無
范例:var?a=\"Hello;
var?b=\"\";
var?c=sting.isEmpty(a);?//c=false
var?c=sting.isEmpty(b);?//d=ture?
var?c=sting.isEmpty(ture);?//e=false?
charAt
程序:charAt(sting.index)
說明:回傳string中index值所指定的字符。
參數:string=字符數
index=數字(回傳回index所指定的字符)
回傳值:字符串或invalid
例外狀況:如果index的值超過字符串的范圍,則回傳空字符串(\"\")
范例:var?a=\"My?name?is?Joe\"
var?b=sting.charAt(a,0);?//b=?\"M\"
var?c=sting.charAt(a,100);?//c=?\"\"
var?d=sting.charAt(34.0);?//d=\"3\"
var?e=sting.charAt(a,\"first\");?//e=invalid
subString
程序:subString(string,startIndex,length)
說明:傳回一個新的字符串來代替所給予的字符串,?這個新字符串給定的索引值開始,它的長度有所給予的length決定。
如果startIndex小于0,則會0來當作索引值。
如果length大于剩余字符的數目,則lenght會由剩余的字符數來代替。
如果startIndex予lenght是浮點數,則會先使用Float.int()來計算正確的整數值。
參數:string=字符數
startIndex=數字
lenght=數字
回傳值:字符串或invalid
例外狀況:如果startIndex大于最后的索引值,則回傳會空字符串(\"\")
如果lenght<=0,傳會空字符串(\"\")
范例:var?a=\"ABCD\";
var?b=String.subString(a,1,2);?//b=\"BC\"
var?c=String.subString(a,2,5);?//c=\"CD\"
var?d=String.subString(1234,0,2);?//d=\"12\"
find
程序:find(string,substring)
說明:傳會所要尋找的字符串substring和原始字符串string相符的第一個字符的索引值。
如果沒有相符,則傳會整數值-1。
兩個字符傳如果是相等的話,是定義為不符合。
參數:string=字符串?
substring=字符串
回傳值:整數或invalid
例外狀況:無
范例:var?a=\"abcde\";
var?b=String.find(a,\"cd\");?//b=2
var?c=String.find(34.2,\"de\");?//c=-1
var?d=String.find(a,\"gz\");?//d=-1
var?e=String.find(34,\"3\");?//e=0
replace
程序:eplace(tring,oldSubString,newSubString)
說明:傳會新字符串,這個新字符串是由和所給予字符串string相符的舊字符傳oldSubString使用新字符串newSubString字符串加以代替。如果兩字符串相等的話,定義為相符。
參數:string=字符串
oldSubString=字符串
newSubString=字符串
回傳值:字符串或invalid
例外狀況:無
范例:var?a=\"Hello?Joe.What?is?up?Joe?\";
var?newName=\"Don\";
var?oldName=\"Joe\";
var?c=String.replace(a,oldName,newName);?//c=\"Hello?Don.What?is?up?Don?\"
var?d=String.replace(a,oldName,newName);?//c=\"Hello?Don.What?is?up?Don?\"
element
程序:element(string,separator)
說明:回傳分隔符號separator所分隔的字符串string的元素數目,空字符串(\"\")是有效的元素,這表示了這程序永遠不會回傳一個小于或等于0得值。
參數:string=字符串
separator=字符串
回傳值:整數或invalid
例外狀況:如果separator是個空字符串,則回傳invalid
范例:var?a=\"My?name?is?Joe;Age?50\";
var?b=String.elements(a,\"\");//b=6
var?c=String.elements(a,\";\");//c=3
var?d=String.elements(\"\",\";\");//d=1
var?e=String.elements(\"a\",\"\");//e=1
var?f=String.elements(\";\",\";\");//f=2
var?g=String.elements(\";;,;\",\";,\");//g=4
separator=;
elementAt
程序:elementAt(string,index,separator)
說明:尋找字符串string的第index個元素,這些元素是由分隔符號separator所加以分開,并回傳相對應的元素。
如果index值小于0,則回傳第一個元素。
如果index值大于元素的數目,則回傳最后一個元素。
如果字符串為空字符串,則回傳空字符串。
如果index值為浮點數,則須先使用Float.int()來計算出正確的索引值。
參數:string=字符串
index=數字
separator=字符串
回傳值:字符串或invalid
例外狀況:如果separator是個空字符串,則回傳invalid
范例:var?a=\"Hello?Joe.What?is?up?Joe?\";
var?b=String.elementAt(a,0,\"\");?//b=\"My\"
var?b=String.elementAt(a,14,\";\");?//c=\"?\"
var?b=String.elementAt(a,1,\";\");?//d=\"Age?50\"
removeAt
程序:removeAt(string,index,separator)
說明:將符合索引值index的分隔號separator與元素有字符串string中移出,并回傳這個新字符串。
如果index值小于0,則回傳第一個元素。
如果index值大于元素的數目,則回傳最后一個元素。
如果字符串為空字符串,則回傳空字符串。
如果index值為浮點數,則須先使用Float.int()來計算出正確的索引值。
參數:string=字符串
element=字符串
index=數字
separator=字符串
回傳值:字符串或invalid
例外狀況:如果separator是個空字符串,則回傳invalid
范例:var?a=\"?A?A;B?C?D\";
var?s=?\"\";
var?c=String.removeAt(a,1,s);?//b=\"A?B?C?D\"
var?d=String.removeAt(a,0,\";\");?//c=\"?B?C?D\"
var?e=String.removeAt(a,14,\";\");?//d=\"A?A\"
replaceAt
程序:replaceAT(string,index,separator)
說明:在特定的index中的元素,使用所給予的元素element來代替,并回傳這個新字符串。
如果index值小于0,則回傳第一個元素。
如果index值大于元素的數目,則回傳最后一個元素。
如果字符串為空字符串,則回傳空字符串。
如果index值為浮點數,則須先使用Float.int()來計算出正確的索引值。
參數:string=字符串
element=字符串
index=數字
separator=字符串
回傳值:字符串或invalid
例外狀況:如果separator是個空字符串,則回傳invalid
范例:var?a=?\"B?C;?E\";
var?s=\"\";
var?d=String.replaceAT(a,\"A\",0,s);?//b=\"A?C;E\"
var?e=String.replaceAT(a,\"F\",5,\";\");?//d=\"B?C;F\"
InsertAt
程序:insertAt(string,index,separator)
說明:將元素element與相對應的分隔符號separator插入與原始字符串string,在特定的element中的元素
如果index值小于0,則0會用來當索引值。
如果index值大于元素的數目,則元素element會附加上字符串string的為端。
如果字符串string為空字符串,則回傳包含所給予元素element的新字符串。
如果index值為浮點數,則需先使用Float.int()來計算出正確的索引值。
參數:string=字符串
element=字符串
index=數字
separator=字符串
回傳值:字符串或invalid?
例外狀況:如果separator是個空字符串,則回傳invalid
范例:var?a=?\"B?C;?E\";
var?s=\"\";
var?b=String.insertAt(a,\"A\",0,s);?//b=\"A?B?C;E\"
var?c=String.insertAt(a,\"X\",3,s);?//c=\"B?C;E?X\"
var?d=String.insertAt(a,\"D\",1,\";\");?//d=\"B?C;D;E\"
var?e=String.insertAt(a,\"F\",5,\";\");?//e=\"B?C;E;F\"
squeeze
程序:squeeze(string)
說明:將字符串string中所有連續的空格減少為一個空格。
參數:stromg=字符串
回傳值:字符串或invalid
例外狀況:無
范例:var?a=\"Hello\";
var?b=\"Bye?Jon.See?you!\";
var?c=String.squeeze(a);?//c=\"Hello\"
var?d=String.squeeze(b);?//d=\"Bye?Jon.See?you!\"
trim
程序:trim(string)
說明:將字符串string中所有開頭與連續的空格刪除。
參數:string=字符串
回傳值:字符串或invalid
例外狀況:無
范例:var?a=\"Hello\";
var?b=\"Bye?Jon.See?you!\";
var?c=String.squeeze(a);?//c=\"Hello\"
var?d=String.squeeze(b);?//d=\"Bye?Jon.See?you!\"
compare
程序:compare(string,string2)
說明:這個程序的回傳值會指出string1與string2在語匯上關系,這個關系是基于自然字集的字符碼之間,其回傳值如下:
如果string1小于string2,傳會-1。
如果string1等于string2,傳會-1。
如果string1大于string2,傳會-1。
參數:string1=字符串
string2=字符串
回傳值:整數或invalid
例外狀況:無
范例:var?a=\"Hello\";
var?b=\"Hello\";
var?c=String.compare(a,b);?//c=0
var?d=String.compare(\"Bye\",\"Jon\");?//d=-1
var?e=String.compare(\"Jon\",\"Bye\");?//e=1
toString
程序:toString(value)
說明:回傳一個能表示所給予的值value的字符串,這個程序跟WML?Script的轉換是一樣的,除了invlaid值會回傳一個\"invalid\"字符串。
參數:value=任意值
回傳值:字符串
例外狀況:無
范例:var?a=string.toString(12);?//?a=\"12\"
var?a=string.toString(true);?//?b=\"true\"
format
程序:format(format,value)
說明:將給予的值value轉換成字符串,并依照所給予的格式format提供的格式化的字符串,這個格式字符串只能由一種特定格式,并能放置于字符串的任何地方,如果超過一種以上的格式需要使用,則能會使用最左邊的格式,至于其他格式則有空字符串代替,這些格式如下:
[width][.precision]type
width參數為非負的是近制整數,這個參數控制與顯現字符的最小數目,如果輸出的字數小于指定的寬度width,則會在字符串的左邊加上空白,直到符合最小寬度的要求,width參數永遠不會是值value被刪減,如果輸出的字數大于特定的寬度或并沒指定寬度的話,value中所有的字符都會被顯現。
precision參數是個非負的十進制整數,這個引號之前必須限價上(.)的符號,其目的是用來設定輸入值的精確度,這個值的解議會跟給予的格式有關:
d?界定數字最小的顯現數目,如果value中數字的數目超過precision的值,輸入值會在其左邊加上0,如果數字的數目超過precision值,value的值并不會被刪減,預設的precision值為1,如果precision值設定為0,而且value頁被轉換成0,則結果將是一個空字符串。
f?界定十進制小數后的數字數目,如果十進制的小數點出現了,在小數點之后至少要有一位數,這個值會被四舍五入到近似的數字數值,預設的precision為6,如果precision為0或小數點(.)后沒有數字,則不會顯現小數點,當value值的小數點后數字數目小于precision的值,字母0為被加入直到填滿欄位(如:String.format(\"%2.3f\",1.2)會是\"1.200\")
s?界定字符所要顯現的最大數目,預設值是顯現所有的字符,當width值大于precision值,width值是可以忽略的,跟width值不同的是,precision只可能會造成浮點數值的四舍五入或輸入值的刪減。
type參數是唯一格式的參數,他出現在任何的格式欄為選項之后,type字符決定了所給予的value將會解譯成整數,浮點數或字符串,支持的type參數如下:
d?整數:輸入值的格式[-]dddd,這里的dddd是一個或以上的十進制數字。
f?浮點數:輸入值的格式[-]dddd.dddd,這里的dddd是一個或以上的十進制數字,在小數點之前的數字數目和數字的大小有關,小數點之后的數字數目和精確度有關。
s?字符串:字符的顯現跟精確度有關。
百分比字符(%)在格式字符串中能使用額外的百分比字符加以表示(%%)。
參數:format=字符串
value=任意值
回傳值:字符串或invalid
例外狀況;無效的格式會回傳invalid值。
范例:var?a=45;
var?b=-45;
var?c=\"now\";
var?d=1.2345678;
var?e=String.format(\"e:%6d\",a);?//e=\"e:45\"
var?e=String.format(\"%6d\",b);?//f=\"-45\"
var?e=String.format(\"e:%6d\",a);?//g=\"0045\"
var?e=String.format(\"%6.4d\",b);?//h=\"-0045\"
var?e=String.format(\"Do?it?%s\",c);?//i=\"Do?it?now\"
var?e=String.format(\"%3f\",d);?//j=\"1.2345678\"
var?e=String.format(\"%10.2f%%\",a);?//k=\"1.23%.\"
var?e=String.format(\"%3f?%2f\",a);?//l=\"1.234567.\"
var?e=String.format(\"%.0d\",0);?//m=\"\"
var?e=String.format(\"%.7d\",\"Int\");?//n=\"invalid\"
var?e=String.format(\"%s\",ture);?//o=\"ture\"
posted @
2006-04-29 09:48 崛起的程序員 閱讀(184) |
評論 (0) |
編輯 收藏
WMLScript腳本程序設計
作為一種編輯語言,WMLScript提供了強大的函數、語句和庫功能,以及外部編輯、訪問控制等支持,同時對程序運行中可能產生的錯誤給出了檢測手段和具體的解決辦法。這些內容屬于WMLScript的腳本程序設計知識和進一步的編程規定,我們本章就對此進行詳細介紹。
5.1?語句
前面我們學習了變量、操作符和表達式,但僅由這些內容并不能完成某個完整的功能,因為他們不能形成完整的操作或處理程序。變量就如同與嚴重的單詞,表達式如語言中的詞組,他們都不能表達一個完整的意思;只有語句,是語言中完整的句子,能夠表達完整的意思并實現某個完整的功能。WML?Script提供了豐富的語句功能,使用這些語句我們可以在WML的卡片中建立交互功能和其他需要的復雜功能。
在WML?Script中,每條語句的后面都需要以一個分號(;)結尾。為了養成嚴謹的編程風格,建議大家編寫腳本時,語句后一定要加上分號(;),這也有助于我們形成一種良好的編程習慣。
WML?Script語句的書寫和排列格式比較自由。我們可以在同一程序行中連續寫上多個語句,也可以把同一語句分成多行排列。WML?Script將根據分號(;)來確定語句的具體內容。
WML?Script的語句主要包括兩類。第一類是基本語句,如空語句、表達式語句、塊語句、變量語句和return語句等;第二類是條件語句,如if語句;第三類是循環語句,如while語句、for語句、break語句和continue語句等。下面我們分別講解這些語句的語法、功能和使用方法。
5.1.1?基本語句
WML?Script基本語句主要用于程序格式控制和變量聲明,其中有些語句我們已經不太陌生了。
空語句
空語句用于定義一個空的程序行,它沒有任何標識符和操作符,也不執行任何操作。它只是以分號(;)結束。其語法格式為:
;
顯然,空語句是一種十分特殊的語句。由是我們為了讓程序具有更好的可讀性,通常在程序中的適當地方加上幾個空語句,以起到分隔或突出的作用。例如,下面的幾行程序中就含有一個空語句:
str=\"Hello\";
val=25;
;
MyVal=val*val+5;
alert(\"Hi,Hi!!!\");
再如,while語句用于判斷一個條件并在條件滿足的時候執行相應的任務,但如果希望條件滿足的時候什么也不作,那么就可以給它配上一個空語句,使之條件滿足的執行空操作:
while(!poll(device));
這實際上是while語句和空語句組成的兩條語句。其中的分號(;)在這里就代表了空語句。這兩條語句的作用是在poll()函數為真()之前一直等待。
表達式語句
表達式語句用于向變量賦值,或進行數學計算,或進行函數調用。表達式語句也是我們最常用的一種語句,語法格式為:
表達式;
下面幾行程序都是合法的表達式語句:
str=\"Hey\"+yourName;
val3=prevVal+4
counter++;
myValue1=counter,myValue2=val3
alert(\"Watch?out!\");
retVal=16*Lang.max(val3,counter);?
塊語句
塊語句使用兩個花括號({?})包含一個語句集,形成一個語句體。WML?Script的許多語句都需要使用塊語句來實現語句體,快語句的語法格式為:
{
語句列表;
}
下面的簡單程序就是使用塊語句的例子:
}
vari=0;
var?x=Lang.abs(b);
popUp(\"Remember!\");
}
變量語句
變量語句用于生命變量并可進行變量的初始化賦值。如果用戶不賦值,那么WML?Script會自動將變量語句生命的變量賦予一個空字符串(\"\")。基本的語法格式為:
var?變量名;
如果像一次生命多個變量,則相鄰變量名之間使用逗號(,)間隔,其語法格式為:
VAR?變量名1,變量名2......,變量名n;
如果想在生命變量時同時初始化變量,則可按如下語法格式書寫:
var?變量名=初始化
為便于大家更好的掌握變量語句,我們給出一個多出使用該語句的程序:?
function?count(stu){
var?result=0;?//聲明變量的同時初始化變量
while(str!=\"\"){
var?ind=0;?//每次循環都初始化一次
//?為退出循環,本塊語句內應當提供修改變量str值的語句
};
return?result
};
function?example(param){
var?a=0;
if(param>a){
var?b=a+1;?//聲明b變量的同時使用a變量初始化b變量
}else{
var?b=a+2;?//聲明c變量的同時使用a變量初始化c變量
};
return?a;?//返回a變量的值
};?
注釋語句
嚴格來講,注釋語句在WML?Script中還不算是真正的語句,它只是一種前指向的規定。不過它也有嚴格的語法和標注方法,所以我們這里還是像其他編程語言處理的一樣,把WML?Script注釋方法以語句的形式介紹一下。
注釋在程序執行的時候沒有任何作用,但是可以用于對程序進行解釋,則增強程序的可讀性。為了形成良好的編程風格,我們應該養成書寫注釋的良好習慣,注釋有兩種表達方式:
(1)通過雙斜線注釋一行,這樣在雙斜先后的字符將成為注釋而不被執行。該注釋行可以單獨一行書寫,也可以放在其他語句的后面。
例如,可以進行如下所示的注釋:
//變量j用于小數每月的天數
j=0;?//我們這里將j賦值為0
(2)通過符號“/*”和“*/”來規定注釋語句,這種注釋方式可以進行多行注釋,符號“/*”和“*/”之間的內容就是注釋語句。例如,可以進行如下所示的多行注釋:
/*我們定義了兩個變量:i和j。其中:
i用于描述每年中的月數,
而j用于描述每月的天數*/
j=0;?/*我們這里將j賦值為0*/
return語句
return語句主要用在函數體中,在函數結束前,可以通過return語句,把函數處理的結果返回給調用函數的語句。它的語法格式如下:
return表達式;
下面的函數給出了應用return語句的例子:?
function?square(x){
if(!(Lang.isFloat(x)))return?invalid;
return?x*x
};?
5.1.2?條件語句
在條件語句中,當滿足某種條件時?,就會執行指定的一些代碼,而在代碼組另外某種條件時,則會執行另外一些代碼。WML?Script的條件語句就是if...else語句,它的一般表達相識如下:
if(條件){
代碼塊1
}
else{
代碼塊2
}?
這樣,當條件滿足時,就執行代碼塊1;如果條件不滿足則執行代碼塊2。代碼塊和代碼塊2中如果只有一個條語句,那么,花括號({?})就可以省略;而如果有多條語句,則必須實用花括號將代碼塊包括在其中。在if...else語句種,其中的else部分是可選的,也就是說,我們可以使用如下的表達形式:
if(條件){
代碼塊
}
這樣,當條件滿足時,就執行代碼塊,如果條件不滿足則什么也不做。
例如,如果我們需要對一個學生的成績進行判定,如果大于等于60分,那么我們就認為該學生成績合格了,反之則認為不合格,同時一并將狀態記錄到變量status種,相應的WMLScript語句如下所示:
if(score>=60)?status=\"pass\";
else?status=\"fail\";
再如,我們可以通過對天氣是否陽光普照(sunShines)的情況進行判斷,來給變量myDay賦值,并累計好天氣(goodDays)的天數。程序如下:
if(sunShines)?{
myDay=\"Good\";
goodDays++;
}else
myDays=\"Oh?well...\";?
5.1.3?循環語句
使用循環語句可以反復執行某個代碼塊,直到循環結束條件滿足后才停止執行。WML?Script中有兩種循環語句:for語句和while語句,同時還有兩終于循環密切相關的操作語言:break語句和continue語句。
for語句
for語句可以創建一個帶條件的循環,它還有3個可選的條件表達式,用于控制循環。這3個條件表達式放在一個括號里,并以分號(;)間隔。for語句的一般語法形式如下:
for(初始表達式;循環條件;遞增表達式){
代碼塊
}
for語句的執行主要包括以下幾個步驟:
(1)執行初始表達式。在一般情況下,初始表達式完成的功能是在循環中對循環計數器賦初值。所以在這種意義上,初始表達式也可以采用“var?變量聲明列表;”的形式來定義。
(2)判斷循環條件。如果循環條件為真(ture),則執行循環體中的語句,即至步驟(3);否則,循環條件為假(false)或者invalid,就結束循環;
(3)執行循環代碼。然后,在執行遞增表達式。一般情況下,我們在遞增表達式中對循環計數器進行處理,最后在返回步驟2執行。
例如,下面的for語句建立了一個循環。初始表達式為定義變量index并付初值0,循環條件為index<100,遞增表達式為每循環一次index增加1。當index增加到100時候,循環結束。程序如下:?
for(var?index=0;index<100;index++){
count+=index;
myFunc(count);
};?
while?語句
while語句也可常見一個循環,它的一般語法表達式如下:
while(循環條件){
代碼塊
}?
while語句的執行過程包括以下幾個步驟:
(1)判斷循環條件是否為真。如果循環條件為真,則執行循環;如果為假或為invalid,則跳出循環。
(2)執行循環中的代碼塊,然后返回步驟(1)
下面的程序就是使用while語句的簡單例子:
var?counter=0
var?total=0
while(counter<3){
counter++;
total+=c;
};?
其中建立的循環僅當變量counter的值小于3時執行,否則就結束循環。
顯然,如果循環條件不能為假或為invalid,那么while循環就會無休止的反復執行下去。因此,我們在代碼塊中一定要有能夠改變循環條件的變量,否則,就很有可能會陷入死循環而不能終止程序,下面就是一個死循環的例子:
var?x=1;
var?y=0;
while(x<=1){
y=x+1;
}?
這個程序中,因為變量x的值在循環中不能發生變化,所以循環條件在判斷的時候永遠為真,所以成為了死循環。因此,對于while語句我們往往使用如下所示的語法形式:
初始表達式
while(循環條件){
代碼塊
遞增表達式
}
這種情況下,while語句的功能和for語句的功能就一樣了,不過用while語句編寫的程序可讀性更強一些。所以我們也可以采用while語句來完成index增加到100的循環。
程序如下:
var?index=0
while?(index<100){
counter+=index;
myFunc(count);
index++;
};?
break語句
為了更好的解決死循環問題,WML?Script項大多數編成語言一樣提供了break語句。break語句可以使程序執行跳出循環。不論是for語句還是while語句,只要在循環中使用了break語句,那么程序執行到break語句后就立即跳出當前循環,然后繼續執行下去。
break語句的予發行時如下:
break;
例如,在下面的函數中我們使用了break語句,它是當index=3時跳出循環。如果不是用該語句,函數中的while循環直到index=6時才可以結束。程序如下:
funcition?testBreak(x){
var?index=0;
while(index<6){
if(index==3)break;
index++
};
retrun?index*x;
;?
continue語句
continue語句的功能和break語句的功能看起來有些類似,但實際上卻不一樣。循環執行時遇到break語句通常是跳出當前循環,但循環執行到continue語句并不跳出當前循環,而是不執行循環中在continue語句后面的代碼塊,直接結束循環的本輪運行,然后馬上開始下一輪循環的運行。
在while語句的循環中,遇到continue語句后,程序會直接判斷循環條件從而開始下一輪循環。在for語句的循環中,遇到continue語句后程序會直接執行遞增表達式,然后判斷循環條件從而開始下一輪循環。
例如,我們想利用for循環求1到10之間偶數的和,其WML?Script語句如下:
var?sum=0;
for?(var?j=1;j<=10;j++){
if(j%2!=0)
continue;
sun+j;
};?
在這個例子中,在j%2!=0的情況下,也就是j為奇數的情況下,程序執行continue語句,這時,并沒有如同break語句一樣跳出循環的運行,而是不執行循環中后面的語句而直接執行遞增表達式開始下一輪循環的執行,這樣,就可以不將其數j的之類即如總和中。
再如,我們想利用while循環求0到4之間出3以外幾個數的和,則可以使用continue語句進行控制。程序如下;
var?index=0;
var?count=0;
while?(index<5){
index++;
if(index==3)
continue;
cont+=index;
};?
這以程序中,當index等于3時,“index==3”為真,所以執行continue語句,不再把此時index的值加大count中,而是開始下一輪的循環。?
5.2?函數的聲明與調用
在WML?Script中,函數是一種能夠完成某種功能的代碼塊,并可以在腳本中被事件處理或被其他語句調用,也可以被WML程序所處理和調用。一般地,當我們編寫WML?Script腳本時,如果腳本中的代碼長度還是很長,則一般還可以根據功能將函數再進行劃分,分成為幾個功能更加單一的函數。雖然說這樣對長代碼的處理方法并不是編寫腳本程序的強制性要求,但通過函數的劃分和運用,我們可以使得WML?Script腳本具有更好的可讀性,也便于我們對腳本程序的編寫與調試。而且,如果在某些腳本中有多處完全相同的代碼塊,那么我們也可以將這些代碼快些為一個函數,然后在腳本中調用這個函數,從而提高代碼的重要性,簡化代碼的編寫工作。
WML?Script的函數共用和Jave語言、C/C++語言的函數有所不同。我們知道,Jave語言、C/C++語言中有函數和過程之分,函數能夠完成一定的功能并有返回值,而過程進可完成一定的功能但沒有返回值。可是,WML?Script中并不區分函數和過程,因為它只有函數,沒有過程。WML?Script的函數完成一定功能后始終有返回值,不過返回值分兩種情況,即非空的返回值和空字符串(\"\")形式的返回值。前者是真正的返回值,后者其實相當于沒有返回值。也就是說,WML?Script中的函數同時具有其他語言中的函數和過程的功能。
5.2.1?函數的聲明
使用函數時,要根據函數的調用使用,而調用函數前必須聲明函數,也就是需要先定義函數。WML?Script中定義函數的一般方式如下:
function函數名(參數列表)
{
代碼塊
};
另外,WML?Script規定使用extern關鍵字來聲明一個外部函數:
extern?function函數名(參數列表)
{
代碼塊
};
從中可以看出,函數的定義有以下3部分組成:
(1)函數名。即函數的名稱,其命名規則應遵守WML?Script的標識規則。調用函數時都是通過函數名進行調用的,所以函數必須要有函數名。
函數命名時,一般要使用能夠描述函數功能的但此來作為函數名,也可以使用多個單詞組合進行命名,這樣做的好處是能夠提高WML?Script腳本的可讀性。
函數名在同一個WML?Script腳本文件里必須是唯一的。如若不然,則會導致函數定義混亂。
(2)參數列表。即調用函數時需要的參數。參數列表通常是可選的,有的函數需要,有的函數可能不需要。參數列表的作用是向函數傳遞一些參數,使得函數可以直接使用這些參數的值。
調用函數的時候,參數個數和類型必須和函數定義示所聲明的參數個數即類型保持一致。而且函數的參數就如同似函數體內的局部變量,它們在函數調用的時候被初始化。
(3)代碼塊。它是函數的主體部分。代碼塊中的代碼包含在以對花括號({?})中,代碼塊可以執行并完成函數的功能。編寫代碼塊是應當遵循WML?Script的編程規則。
有時,函數需要返回一個值給調用函數的語句,則應該在代碼塊的后面一行使用return語句,返回所需的數值。
與C/C++等語言類似,WML?Script的函數是可以嵌套的,以就是說,在一個函數中還可以調用其他函數。但是,函數聲明是不能嵌套,這是WML?Script的強制性規定。
下面幾行語句就是定義函數的簡單例子:
function?currencyConverter(currency,exchangeRate)
{
return?currency*exchangeRate;
};
其中,該函數的名稱為currencyConverter,參數有currency和exchangeRate兩個,函數代碼塊包含一條語句,用于返回currency和exchangeRate的乘積。
下面是一個使用extern定義外部函數的例子。其中函數名為textIt,它沒有參數,函數體中定義了兩個賦值變量,一個賦整數,一個賦函數值:
extern?function?testIt(){
var?USD=10;
var?FIM?=currencyConverter(USD,5.3)
};
5.2.2?函數的調用
編寫好的函數必須經過合法的調用,才可以發揮它應用的作用。函數調用將返回一個值,比如一個計算結果。WML?Script中的函數主要可以分為內部函數、外部函數和庫函數,下面我們就介紹這3類函數的調用方法。
內部函數
所謂內部函數是指函數的定義與其調用函數在同一個腳本文件內的函數,對內部函數的調用稱為內部調用。內部函數的調用非常簡單,只需提供函數名和所需參數值即可,參數值必須和函數定義時指定的參數個數即類型一致。而且函數調用需要使用操作符來接收或處理被調用的返回值。
內部函數可以在其定義之前調用,也可以在其定義之后調用。例如,下面就是一個在函數定義之后調用的例子。?
function?test1(val){
return?val*val;
};
function?test2(param){
return?test1(param+1);
};?
這個例子中定義了兩個函數test1和test2。test1函數用于計算給定參數值的平方并將結果返回;test2函數將給定的參數值加1,然后這個和為參數值,來調用test1函數,得到結果后在將給結果返回到調用test2函數的語句。
注意,本例中test2函數調用了test1函數,這種在函數中調用其他函數的方法稱為函數調用嵌套。WML?Script的內部函數、外部函數和庫函數都支持嵌套調用,后面我們專門介紹這方面的內容。
外部函數
外部函數使一個在WML?Scrupt外部文件中定義的函數。調用外部函數的方法與調用內部函數的方法基本類似,不同之處在于調用處外部函數時一是要指定外部文件的地址即名稱,二是要在調用的外部函數名的前面加上外部文件的名稱。
WML?Script規則使用use?url來指定外部文件,語法格式為:
use?url還有外部函數的外部文件名?外部文件所在的URL;
這樣,WML?Script的預編譯頭就可以將外部文件映射為一個可以在內部使用的標識。然后,使用這個標識并加上井號鍵(#)和標準的函數調用即可實現外部函數調用,語法格式為:
外部文件名#外部函數(參數列表);
例如,http://www.host.com/script下有我們需要的外部文件,名為OtherScript,所以我們可使用use?url來指定該文件:
use?url?OtherScript\"http://www.host.com/script\"
這一外部文件中含有我們需要調用的外部函數testme,則可采用“外部文件名#外部函數(參數列表)”的形式來調用它:
OtherScript#testme(param+1);
這個例子完整的寫出來,就是下面的程序:
use?url?OtherScript\"http://www.host.com/script\"
function?test(param){?
return?OtherScript#testme(param+1);
};
庫函數
特別指定,WML?Script的庫函數一律是指它的標準庫函數。因為與標準庫函數對應,WML?Script還有一些非標準的庫函數。我們這里先介紹標準庫函數,非標準庫函數后面再介紹。
所有庫函數都有所數的庫,函數的庫中通常含有一類函數。因此,調用某個庫函數時,一要指定它的庫名,二要指定它的函數名。WML?Script規定,調用標準庫函數時可以通過在函數庫的名字后面加上句點號(.)和庫函數的標準調用來實現,語法格式為:
函數庫名.函數名(參數列表);
例如,WML?Script的浮點庫即Float庫中有一個開根方的函數sqrt,該函數只有一個參數,那么調用squrt庫函數的方法為:
Float.sqrt(number);//這里要求number大于或等于0
下面給出了調用庫函數的簡單例子。首先一param參數值調用Lang.abs()函數,返回結果加1后再作為參數調用Float.sqrt()函數,它的返回結果作為內部函數test的返回值:
function?test(param){
return?Float.sqrt(Lang.abs(param)+1);
};
2.3?函數的嵌套調用
WML?Script的函數定義都是互相平行、獨立的,定義函數的時候我們不能在一個函數內定義另外一個函數,也就是說,函數定義是不能嵌套的。但是,函數調用確是可以嵌套的,也就是說,我們可以在調用一個函數的過程中調用另外一個函數。
它的執行過程是:
(1)執行a函數開頭部分;
(2)遇到調用b函數的操作語句,流程則專區執行b函數;
(3)執行b函數開頭部分;
(4)遇到調用c函數的操作語句,流程則專區執行c函數;
(5)執行b函數,如果沒有其他嵌套的函數,則完成c函數的全部操作;
(6)返回調用c函數的語句,即返回到b函數;
(7)繼續執行b函數中尚未執行的操作,直到b函數結束;
(8)返回a函數中調用b函數的語句;
(9)繼續執行a函數的剩余操作,直到函數結束。
function?myFunC(param1){
return?param1*param1=Float.squt(Lang.abs(param)+1);
};
function?myFunB(param0){
return?myFunC(param0+1)*|param0+12;
};
function?myFunA(param){
return?myFunB(param*param+1);
};
5.3?預編譯
WML?Script的預編譯主要用于在編譯階段控制編譯器的行為。與編譯頭一般在文件開頭和函數聲明之前指定,WML?Script規定所有的預編譯頭都是一關鍵詞use加上指定的預編譯屬性進行指定。
在大多數的編程中,我們比較長用的預編譯行為主要涉及外部文件聲明、訪問權和Meta信息設置。
5.3.1?外部文件
我們知道,使用URL地址可以定位一個WML?Script文件。利用該URL地址;在WML?Script編程中我們可以通過預編譯來調用WML?Script的外部文件,外部文件預編譯頭的聲明方法是use?url,其語法格式如下:
use?url外部文件名?\"URL\"地址
這樣,我們在當前文件的編程中就可以使用該預編譯頭聲明的外部文件,從而可以調用該外部文件的函數。其語法格式為:
外部文件名#函數名(參數列表);
例如,我們希望在當前的WML?Script程序中調用OtherScript外部文件中的check()函數,而且我們知道OtherScript文件的URL地址為http://www.host.com/app/script。因此,我們可以使用use?url來聲明這一外部文件:
use?url?OtherScript\"http://www.host.com/script\"
隨后,我們就可以在程序中調用OtherScript中的check()函數了:
function?test(par1,par2)
{
return?OtherScript#check(par1,parr2);
};
其中調用執行的過程如下:
(1)找到WML?Script外部文件的URL地址;
(2)當前函數從指定的URL地址值裝載外部文件;
(3)檢測外部文件的內容,并執行其中的check()函數。
ure?url?預編譯頭指定的外部文件名在當前程序中必須唯一,用戶不能指定不同URL地址的同名外部文件,否則在調用外部文件時就會發生混亂。
另外,use?url預編譯頭中的URL地址也可以是相對URL地址。相對URL的起始位置是當前程序文件所在的位置,并在此基礎上根據URL進行定位。
如果URL地址中的字符包含有轉義字符,則WML?Script將根據轉義要求進行轉義。不過,程序在編譯的時候編譯器并不會對他們進行轉義,而是在程序執行時完成,檢查URL格式和URL地址的有效性。
5.3.2?訪問權限
我們可以使用訪問權限預編譯設保護文件的內容,實現訪問控制。WML?Script編程中,必須在調用外部函數之前使用訪問權限預編譯頭聲明外部文件的訪問權限。不過,WML?Script訪問權限檢查的缺省值是不進行檢查,即disabled.但訪問權限一經聲明,以后當調用外部函數的時候,編譯器就會檢查外部文件的訪問權限,以決定調用這是否有權使用該文件及其內含函數。
訪問權限預編譯頭的聲明方法是use?access,其語法格式如下:
use?access?domain操作域名?path操作路徑:
訪問權限預編譯頭通過指定domain和path屬性來決定編譯器將要進行什么樣的檢查工作。如果文件有domain或者path屬性,那么文件所在的URL就必須和屬性中的值一致。比較時,域和路徑都依據URL大寫規則進行比較。具體的比較預則如下:
(1)操作域與URL中的域后綴相匹配。與后綴匹配是值所有的子域從后向前都必須一致。例如:www.wapforum.org和wapforum.org相匹配,而與forum.org并不匹配。
(2)操作路徑和URL中的路徑前綴相匹配。路徑前綴匹配是值從前向后必須一致。例如:“/X/Y”與“/X”相匹配,而不是和“/XZ”相匹配。
(3)卻省的domain數行為當前的文件域,就是“/”。
不過,為了簡化編程,有時WMLScript并不需要直到外部文件的絕對路徑,我們只需提供文件的相對URL即可,用戶瀏覽器執行程序是卡相對路徑自動轉換為絕對路徑,根據路徑屬性進行匹配。例如:如果訪問權限預編譯頭及其指定屬性為:
use?access?domain\"wapforum.org\"path\"/finance\";
則可以使用以下的路徑來調用指定文件中的外部函數,它們都符合相對URL地址匹配規則:
http://wapforum.org/finance/money.cgi
http://www.?wapforum.org/finance/money.cgi
http://www.?wapforum.org/finance/demos/packages.cgi?x+123&y+456
而以下的路徑調用則非法的,因為它們或者操作域不對,或者URL地址不能與指定的相對URL相匹配:
heep//www.test.net/finance
http//www.qapforum.org/internal/foo.wml
需要強調指出的是,WML?Script規定,同一程序中只能定義一個訪問權限與編譯頭,否則就會導致編譯錯誤。
5.3.3?Meta?信息
我們還可以通過與編譯頭的形式聲明WML?Script文件的Meta信息。Meta信息主要用于指定文件所需Mete屬性的屬性名(Property?name)、屬性值(Content)以及文件的配置(信息),屬性都屬于字符串類型的數據。Mate信息域編譯頭使用use?meta聲明,其語法格式為:
usr?meta?屬性?該屬性Meta信息:
Meta的屬性主要包括Name、HTTP?Equiv和User?Agent三種,下面我們分別講解它們的聲明方法:
(1)Name。該屬性用于指定服務器使用的Meta信息。這些信息僅供服務使用,用戶瀏覽器并不理會這些信息。
例如,以下Name屬性的Meta信息指定了服務器的創建時間:
use?meta?name?\"Created\"\"26-June-2000\";
該信息只會作用于服務器,而不會影響用戶瀏覽器的操作。
(2)HTTP?Equiv。該屬性用于指定需要解釋為HTTP頭的Meta信息。對于已經編譯的文件來說,當它到達用戶瀏覽器前,WML?Script將根據HTTP?Equiv屬性指定的Meta信息將文件轉換為WSP或HTTP的響應頭,進行文件的解釋和執行。
例如,以下聲明的http?equiv屬性指定按照腳本語言的關鍵字來解釋當前文件:
use?meta?http?equiv\"Keywords\"\"Script,Language\";
(3)User?Agent。該屬性用于定義用戶瀏覽器使用的數據類型。例如:
use?meta?user?agent\"Type\"\"Test\";
它指定當前數據必須立即發送給用戶瀏覽器,然后馬上清除掉。
5.4?執行時的錯誤檢測與處理
WML?Script函數的功能提供用戶服務,并希望用戶界面能在任何的狀況下運作順利,因此錯誤的處理是最大的課題,這表示了語言可能不提供預期的機制,如他應該可以防止錯誤發生或提醒用戶注意并采取適當的動作,種植儲蓄執行是最后的手段。下面幾個小節列出了當為碼下載并執行時會發生的錯誤,一些程序上的錯誤并不在談論的范圍(如無窮循環),像這類的例子就需要手動來終止。
5.4.1?錯誤檢測
錯誤檢測工具能讓你檢測錯誤但會干擾系統的動作,因為WML?Script是弱格式語言,所以由一些特殊功能的工具來檢測有invalid數據格式所引起的錯誤:
檢測給定的變量包含的是正確值:WML?Scritp含有格式確認函數庫程序如:Lang.isInt()Lang.isFloat()、Lang.parseInt()、Lang.parseFloat。
檢測給定的變量包含的只是正確的格式:WMLScript含有運算符typeof與isvalid能讓你使用。
5.4.2錯誤處理
錯誤處理是在發生錯誤之后,有些狀況是錯誤檢測無法防止的,如內存限制后外部信號等,或者是數據很難處理,如溢出(overflow)或虧失(underflow),而這些狀況可以分為兩類:
嚴重錯誤(fatalerror):這種錯誤會造成程序終止,因為WML?Scritp程序會讓一些用戶界面調用,程序終止通常會跟調用它的用戶界面發出信號,用戶界面就會告知用戶這個錯誤。
錯誤(non-fatalerrow):這種錯誤會把信號傳回程序,如一些特殊的值,然后由程序決定所要采取的行動。
下列的錯誤是根據他們的嚴重性來區分。
5.4.3?嚴重錯誤(fatalerror)
下面的小節會討論WML?Script的嚴重錯誤。
位碼錯誤(bytedode?error)
這些錯誤跟位碼與由WML?Script位碼解譯器所執行的指令有關他們指出了錯誤的元素群、無效的指令、指令所使用的參數無效,或指令無法執行。
驗證錯誤(verification?failed)
說明:調用的程序中的特定位碼無法通過驗證。
如何發生:每次程序試著用外部程序。
范例:var?a?=?3*OtherScript#doThis(param)
嚴重性:嚴重。
判定狀況:當檢測位碼驗證式。
解決方法:終止程序與WML?Script解譯其調用者的錯誤信號。
說明:調用一個函數庫程序時發生嚴重錯誤。
如何發生:每次調用函數庫程序。
范例:var?a?=?string.format(param)
嚴重性:嚴重。
判定狀況:無
解決方法:終止程序與WML?Script解譯其調用者的錯誤信號。?
說明:調用函數參數的數目跟被調用函數的參數數目不符合。
如何發生:調用外部程序。
范例:編譯器參生一個無效的參數給予指令使用,或者被調用的程序參數數目改變了。
嚴重性:嚴重。
判定狀況:無
嚴重性:嚴重。
解決方案:終止程序與WML?Script解譯器調用著的錯誤信號。
說明:?在特定的程序中找不到所需要的外部程序。
如何發生:調用外部程序。
范例:?var?a?=3*OtherScript#doThis(param)
嚴重性:嚴重。
判定狀況:無
解決方案:終止程序與WML?Script解譯器調用著的錯誤信號。
說明:?由于在網絡服務器的程序存取又無法修復的錯誤或特定程序并不在網絡服務器中所引起的程序無法載入。
如何發生:調用外部程序。
范例:?var?a?=3*OtherScript#doThis(param)?
嚴重性:嚴重。
判定狀況:無
解決方案:終止程序與WML?Script解譯器調用著的錯誤信號。
說明:?存取錯誤,所調用的外部程序加了保護。
如何發生:調用外部程序
范例:var?a?=3*OtherScript#doThis(param)?
嚴重性:嚴重。
判定狀況:無
解決方案:終止程序與WML?Script解譯器調用著的錯誤信號。
說明:?因為程序錯誤造成stack?underflow。?
如何發生:程序要取出(pop)一個空堆
范例:?當組譯器產生錯誤碼。
嚴重性:嚴重。
判定狀況:無
解決方案:終止程序與WML?Script解譯器調用著的錯誤信號。
說明:執行調用Lang.abort()?是發生的錯誤。
如何發生:每當程序調用Lang.abort()函數。
范例:?Lang.abort(\"unrecoverable?error\")
嚴重性:嚴重。
判定狀況:無
解決方案:終止程序與WML?Script解譯器調用著的錯誤信號。
說明:發生堆棧溢出。?
如何發生:程序資源太多或要推入太多的變量到運算之中。
范例:?function?f|(x)(f(x+1););
嚴重性:嚴重。
判定狀況:無
解決方案:終止程序與WML?Script解譯器調用著的錯誤信號。
說明:沒有多余的內存可供解譯器使用。
如何發生:作業系統無法配置多余的空間給解譯器適使用。
范例:?function?f(x){
x=x+\"abcdefghijklmnopqrstuvxyz\";
f(x)?;
};
嚴重性:嚴重。
判定狀況:無
解決方案:終止程序與WML?Script解譯器調用著的錯誤信號。
說明:用戶終止程序的執行(如按下reset鈕)
如何發生:隨時。
范例:?當應用程序正在執行是用戶按下reset鈕。
嚴重性:嚴重。
判定狀況:無
解決方案:終止程序與WML?Script解譯器調用著的錯誤信號。
說明:當程序執行中,發生了外部嚴重的錯誤。
如何發生:隨時。
范例:?電力微弱,系統自動。
嚴重性:嚴重。
判定狀況:無
解決方案:終止程序與WML?Script解譯器調用著的錯誤信號。
5.4.4?一般錯誤(Nonfatal?error)
下面說明了WML?Script的一般錯誤:
計算錯誤(computational?error)
這些錯誤是由于WML?Script數學上的運算所造成。
除以零(divide?by?zero)
說明:發生了除以零的狀況
如何發生:當程序中有除以零的狀況。
范例:var?a=?10;
var?b=?0;
var?x=?a/b;
var?y=?a?div?b;
var?z=?a%b;
a/=b;
嚴重性:?一般。
判定狀況:高
解決方案:產生結果為invalid。
說明:發生了除以零的狀況
如何發生:程序要執行浮點數運算。
范例:var?a?=?Float.precision();
var?b?=?Float.precision();
var?c?=?a*?b
嚴重性:一般。
判定狀況:高,在某些狀況很困難。
解決方法:產生的結果為浮點數值0.0
常數參考錯誤(constant?reference?error)
說明:所參考的浮點數實字為not?a?number。
如何發生:程序試著存取一個浮點數實字但組譯器產生了not?a?number的浮點數常數。
范例:參考浮點數常數。
嚴重性:一般。
判定狀況:高
解決方法:這會產生invalid值。?
說明:參考的浮點數實字不是正無窮大就是負無窮大的浮點數常數。
如何發生:程序試著存取一個浮點數實字但組譯器產生了正無窮大或負無窮大的浮點數常數。
范例:參考浮點數常數。
嚴重性:一般。
判定狀況:高
解決方法:這會產生invalid值。
說明:需要參照浮點數值所發生的錯誤。
如何發生:程序需要使用浮點數值但環境值支持整數值。
范例:var?a?=?3.14;
嚴重性:一般
判定狀況:高?
解決方法:這會產生invalid值。?
轉換錯誤
這個錯誤的發生同WML?Script所支持的自動轉換有關。
說明:欲轉換成整數值,但這個值超過整數所能接受的范圍(正或負)。
如何發生:程序試著自動轉換成整數時。
范例:?var?a?=?-\"99999999999999999999999999999999999999999\";
嚴重性:一般?
判定狀況:高
解決方法:這會產生invalid值。?
說明:欲轉換成浮點數,但這個值小于浮點數所能接受的范圍(正或負)。
如何發生:程序時值自動轉換成浮點數時。?
范例:var?a?=?-\"99999999999999999999999999999999999999999\";?
嚴重性:一般?
判定狀況:高?
解決方法:這會產生invalid值。?
說明:欲轉換成浮點數,但這個值小于浮點數所能接受的范圍(正或負)。
如何發生:程序時值自動轉換成浮點數時。
范例:var?a?=?-\"99999999999999999999999999999999999999999\";?
嚴重性:一般?
判定狀況:高
解決方法:這會產生浮點數0.0。
6.5?URL函數庫
名稱:URL
說明:這個函數庫包含了處理絕對的URL與相對URL的程序,一般的URL語法如下:://:/;?#
isValid
程序:isValid(url)
說明:如果給予的url值是正確的URL語法,則回傳ture,否則回傳false
絕對與相關URL都能支持
相關URL不會被轉成絕對URL
參數:url=字符串
回傳值:布爾值或invalid
例外狀況:無
范例:var?a=URL.isValid
(\"http://www.acme.com/script#func()\");?//a=ture
var?b=URL.isValid(\"../common#test()\");?//b=ture
var?c=URL.isValid
(\"experimental?://www.acme.com/pub\");?//c=false?
getScheme
程序:getScheme(url)
說明:回傳給予url的調用方式scheme
絕對與相關URL都能支持
相關URL不會被轉成絕對URL
參數:url=字符串
回傳值:字符串或invalid
例外狀況:如果遇到不正確的URL語法,則回傳invalid
范例:var?a=URL.geScheme(\"http://w.a.com\");?//a=\"http\"
var?b=URL.getSceme(\"w.a.com\");?//b=\"\"
getHost
程序:getHost(url)
說明:回傳給予url的主機
絕對與相關URL都能支持
相關URL不會被轉成絕對URL?
參數:url=字符串
回傳值:字符串或invalid
例外狀況:如果遇到不正確的URL語法,則回傳invalid
范例:var?a=URL.geHost(\"http://www.acom.com/pub\");?//a=\"www.acm.com\"
var?b=URL.getHost(\"path#fray\");?//b=\"\"
getPort
程序:getPort(url)
說明:回傳給予url的端口(port)
如果port沒有制定,則回傳空字符串
絕對與相關URL都能支持
相關URL不會被轉成絕對URL?
參數:url=字符串
回傳值:字符串或invalid
例外狀況:如果遇到不正確的URL語法,則回傳invalid
范例:var?a=URL.getPort(\"http://www.acom.80/path\");?//a=\"80\"
var?b=URL.getPort(\"http://www.acom./path\");?//b=\"\"
getPath
程序:getPath(url)
說明:回傳給予url的路徑(path)
參數:url=字符串
回傳值:字符串或invalid
例外狀況:如果遇到不正確的URL語法,則回傳invalid
范例:var?a=URL.getPath(\"http://w.a.com/home/sub/comp#frag\");?//a=\"/home/sub/comp\"
var?b=URL.getPath(\"../home/sub/comp#frag\");?//b=\"../home/sub/comp\"
getParameters
程序:getParameters(url)
說明:回傳給予url的路徑(parameter)
如果沒有指定參數,則回傳空字符串
絕對與相關URL都能支持
相關URL不會被轉成絕對URL?
參數:url=字符串
回傳值:字符串或invalid
例外狀況:如果遇到不正確的URL語法,則回傳invalid
范例:var?a=URL.getParameters(\"http://w.a.c/scr;3;2?x=1&y=3\");?//a=\"3;2\"
var?b=URL.getParameters(\"../scr3;2?x=1&y=3\");?//b=\"../home/sub/comp\"
getQuery
程序:getQuery(url)
說明:回傳給予url的詢問部分(query)?
如果沒有指定的詢問部分,則回傳空字符串
絕對與相關URL都能支持
相關URL不會被轉成絕對URL?
參數:url=字符串
回傳值:字符串或invalid
例外狀況:如果遇到不正確的URL語法,則回傳invalid
范例:var?a=URL.getParameters(\"http://w.a.c/scr;3;2?x=1&y=3\");?//a=\"3;2\"
getFragment
程序:getFragment(url)
說明:回傳給予url的片斷(fragment)
如果沒有指定片斷,則回傳空字符串
絕對與相關URL都能支持
相關URL不會被轉成絕對URL?
參數:url=字符串
回傳值:字符串或invalid
例外狀況:如果遇到不正確的URL語法,則回傳invalid
范例:var?a=URL.getFragment(\"http://www.acom.com/cont#fray\");?//a=\"fray\"
getBase
程序:getBase()
說明:回傳次WML?Script程序的絕對URL(沒有fragment的部分)。
參數:無
回傳值:字符串
例外狀況:無
范例:var?a=URL.getBase();?//Result;
\"http://www.acme.com/test.scr\"
getReferer
程序:getReferer()
說明:回傳調用目前程序資源的最小相關URL(與目前程序的基本URL的相關)
內部程序調用并不會改變參照者
如果目前的程序并沒有參照者,則回傳空字符串
參數:無
回傳值:字符串
例外狀況:無
范例:var?base=URL.getBase();?//base
=\"http://www.acme.com/current.scr\"
var?prferer=URL.getReferer();?//referer=\"app.wml\"
resolve
程序:resolve(baseUrl,embeddedUrl)
說明:根據RFC2396的文件,由給予的基本base與插入embeddedUrl回傳絕對URL
參數:baseUrl=字符串
embeddedUrl=字符串
回傳值:字符串或invalid
例外狀況:如果遇到不正確的URL語法,則回傳invalid
范例:var?a=URL.resolve(http://www.foo.com/,\"foo.vcf\");?//a=\"http://www.foo.com/foo.vcf\"
escapeString
程序:escapeString(string)
說明:這個程序會將所給與string字符串之中的特殊字符使用十六進制逃脫序列來替代(你必須使用量為逃脫序列格式%xx),這些逃脫字符如下:
控制字符(control?characters):US-ASCII編碼的字符00-1F與7F
空格(Space):US-ASCII碼編字符20十六進制
保留字(Reserved):\";\"|\"/\"|\"?\"|\":\"|\"@\"|\"=\"|\"+\"|\"$\"|\",\"
Unwise:\"{\"|\"}\"|\"|\"|\"\\\"|\"\"|\"[\"|\"]\"|\"`\"
Delimes:\"<\"|\">\"|\"#\"|\"%\"|\"<>\"
給予的字符串如果已經是使用逃脫自負,則不會執行URL解析
參數:string=字符串
回傳值:字符串或invalid
例外狀況:如果字符串string含有非US-ASCII的字符,則回傳invalid
范例:var?a=URL.escapeString
(\"http://w.a.c/dck?x=u007ef#crd\");
//?a=\"http%3a2f%2fw.a.c%2fdck%3fx%3def%23crd\"
unescapeString
程序:unescapeString(string)
說明:這個程序會將所給與string字符串之中每個可能是由URL.escapeString()?程序所產生的逃脫序列使用它所代表的字符加以替代。
參數:string=字符串
回傳值:字符串或invalid
例外狀況:如果字符串string含有非US-ASCII的字符,則回傳invalid
范例:var?a=\"http%3a2f%2fw.a.c%2fdck%3fx%3def%23crd\";
var?b=URL.unescapeString(a);?//b
=\"http://w.a.c/dck?x=12#crd\"
loadString
程序:loadString(url,contentType)
說明:回傳有所給予的絕對URL與contenttype所指出的內容。
如果內容格是不是下列法則所規范的話,則是錯誤的:
你只能界定一種內容格式,整個字符串必須和一種內容格式相符,而?且你不能有額外的前或后空格。
格式必須是正文,但次格式沒有限制,格式的開頭一定是\"text/\"。
這個程序的動作如下:
文件的內容會載入使用給予的contentType與url,其他所需的數形式有使用用戶界面的預設面。
如果載入成功而且回傳的內為格式與所給予的contentType相符,則內文會被轉換成字符串再回傳。
如果載入成功或回傳的內文格式不正確的話,則會回傳特定的錯誤碼。
參數:url=字符串?
contentYype=字符串
回傳值:字符串、整數或invalid
例外狀況:如果載入失敗其回傳的錯誤碼和所使用的URL?Scheme有關
如果使用HTTP或WSP架構,會回傳HTTP錯誤碼。
如果給予的contentType錯誤的話,則會回傳invalid
范例:var?a=\"http%3a2f%2fw.a.c%2fdck%3fx%3def%23crd\";
var?b=URL.unescapeString(a);?//b
=\"http://w.a.c/dck?x=12#crd\"
loadString
程序:loadString(url,contentType)
說明:回傳有所給予的絕對URL與contenttype所指出的內容。
如果內容格是不是下列法則所規范的話,則是錯誤的:
你只能界定一種內容格式,整個字符串必須和一種內容格式相符,而?且你不能有額外的前或后空格。
格式必須是正文,但次格式沒有限制,格式的開頭一定是\"text/\"。
這個程序的動作如下:
文件的內容會載入使用給予的contentType與url,其他內文所需的數形式有使用用戶界面的預設面。
如果載入成功而且回傳的內容為格式與所給予的contentType相符,則內文會被轉換成字符串再回傳。
如果載入成功或回傳的內文格式不正確的話,則會回傳特定的錯誤碼。
參數:url=字符串?
contentYype=字符串
回傳值:字符串、整數或invalid
例外狀況:如果載入失敗其回傳的錯誤碼和所使用的URL?Scheme有關
如果使用HTTP或WSP架構,會回傳HTTP錯誤碼。
如果給予的contentType錯誤的話,則會回傳invalid
范例:var?myUrl=\"http://www.acme.com/vcards/myaddr.vcf\";
myCard=URL.loadString(myUrl,\"text/x-vcard\");
6.6?WML瀏覽器函數庫
名稱:WML?Brower
說明:這個函數庫所包含的程序是讓WML?Script用來存取與WML相關的內文,這些程序不能有任何的副作用,并在下列的狀況下回傳invalid值。
系統不支持WML瀏覽器。
WML瀏覽器無法使用WML?Script解譯器。
getVar
程序:getVar(name)
說明:回傳目前瀏覽器內文的所給予名稱name的變量值。
如果所指定的變量不存在,回傳一個空字符串。
變量名稱必須依照WML語法來使用。
參數:name=字符串
回傳值:字符串或invalid
例外狀況:如果變量名稱不合語法,則回傳invalid
范例:var?a=WMLBrowser.getVar(\"name\");
//?a\"Jon\"或者變量的值
setVar
程序:setVar(name,value)
說明:在目前的瀏覽器之中,如果所給予名稱name的變量,它的值同給予的值value設定的一樣的話,回傳ture,否則回傳false。
變量名稱必須依照WML語法來使用。
變量值必須是合法的XML?CD?ATA
參數:name=字符串
value=字符串
回傳值:布爾值或invalid
例外狀況:如果變量名稱或它的值不合語法,則回傳invalid
范例:var?a=WMLBrowser.setVar(\"name\",Mary);?//?a=true
go
程序:go(url)
說明:將給予的url所標記的內文載入,這個程序予WML的GO動作意思相同。
如果所給予的url字空字符串(\"\"),則不會載入任何內文。
go()與prev()函數庫程序會互相推翻,在回傳控制與WML瀏覽之前都可以加以調用多次。
只有最后的調用設定的會保持作用,如果最后的調用為go()或prev(),其所設定的url為空字符串(\"\"),所有的要求都會被取消。
這個程序回傳空字符串。
參數:url=字符串
回傳值:字符串或invalid
例外狀況:無
范例:varcard=\"http://www.acme.com/loc/app.dck#start\";WMLBrowser.go(card
)
prev
程序:prev()
說明:告訴WML瀏覽器回到先前的WML?Card,這個程序的功能與WML中的prev動作一樣。
go()與prev()函數庫程序會互相推翻,在回傳控制與WML?瀏覽之前都可以加以調用多次。
只有最后的調用設定是會保持作用,如果最后的調用為go()或prew(),其所設定的url為空字符串(\"\"),所有的要求都會被取消。
這個程序回傳空字符串。
參數:無
回傳值:字符串或invalid
例外狀況:無
范例:WMLBrowser.prev();
newContext
程序:newContext()
說明:將目前WML瀏覽器的內文清除并回傳一個空字符串,這個程序的公用與WML的NEWCONTEXT屬性一樣。
參數:無
回傳值:字符串或invalid
例外狀況:無
范例:WMLBrowser.newContext();
getCurrentCard
程序:getCurrentCard()
說明:回傳目前WML瀏覽器所處理card的最小相關URL,如果WML?deck所包含目前程序的基本地址不同的話,則此程序會回傳絕對URL。
參數:無
回傳值:字符串或invalid
例外狀況:如果沒有目前的card,則回傳invalid。
范例:var?a=WMLBrowser.getCurrentCard();//?a=\"deck#input\"
refresh
程序:refresh()
說明:強制WML瀏覽器更新它的內文并回傳一個空字符串,而用戶界面會加以更新以反應更新后的內容,這個程序與WML中的refresh功能一樣。
參數:無
回傳值:字符串或invalid
例外狀況:無
范例:WMLBrowser.setVar(\"name\",\"Zorro\");
WMLBrowser.refresh();
6.7?Dialog函數庫
名稱:對話
說明:這個函數庫包含典型的用戶界面程序。
prompt
程序:prompt(message,defaultInput)
說明:顯示給予的信息message與用戶輸入的提示符號,defaultInput參數包含了用戶輸入所需的初始內文,回傳用戶輸入。
參數:message=字符串
defaultInput=字符串
回傳值:字符串或invalid
例外狀況:無
范例:var?a=\"09-555?3456\";?var?b=Dialogs.prompt(\"Phome?number\";a);
confirm
程序:confirm(message,ok,cancel)
說明:顯示所給予的信息message與兩個選項:ok與cancel,等待用戶選取其中一個,如果是ok則回傳false。
參數:message=字符串
ok=字符串
cancel=字符串
回傳值:布爾值invalid
例外狀況:無
范例:function?onAbort(){return?Dialogs.confirm(\"Are?you?sure?\"),\"Yes\",\"No\";};
alert
程序:alert(message)
說明:顯示所給予的信息message給用戶,等待用戶確定并回傳一個空字符串。
參數:message=字符串
回傳值:字符串或invalid
例外狀況:無
范例:function?testValue(textElement){
if?(String.length(textElement)>8)?{
Dialogs.alert(\"Enter?name?<8?chars!\");
};
};
6.8?函數庫總結?
函數庫?
函數庫名稱:
Lang
Float
String
URL
WML?Browser
Dialogs
函數庫與他們的程序:
Lang函數庫
Abs
Min
Max
ParseInt
ParseFloat
IsInt
IsFloat
MaxInt
MinInt
Float
Exit
Abort
Random
Seed
CharacterSet
Float?函數庫
Int
Ploor
Ceil
Pow
Round
Sqrt
MaxFloat
MinFloat
String?函數庫
Length
IsEmpty
CharAt
SubString
Pind
Replace
Elements
ElementAt
RemoveAt
ReplaceAt
InsertAt
Squeeze
Frim
Compqre
ToString
format
URL?函數庫
IsValid
GetScheme
GetHost
GetPort
GetPath
GetParameters
GetQuer
GetFragment
GetBase
GetReferer
Resolve
EscapeString
UnescapeString
loadString
WML Browse函數庫
Get?Var
SetVar
Go
Prev
NewContext
GetCurrentCard
Refresh
Dialogs函數庫
Prompt
Confirm
Alert
posted @
2006-04-29 09:47 崛起的程序員 閱讀(381) |
評論 (0) |
編輯 收藏
WML?Script語法基礎
WML?Script是屬于無限應用協議WAP應用層的一部分,使用它可以向WML卡片組和卡片中添加客戶端的處理邏輯,目前最新的版本是1.1版。WML?Script1.1是在歐洲計算機制造商協議會制定的ECMAScript腳本語言的基礎上,經過修改和優化而指定的。它能夠更好的支持諸如移動電話類的乍帶寬通信設備,在WML編程中使用WML?Script可以有效的增強客戶端應用的靈活性,而且,我們也可以把WML?Script作為一個工具使用,開發出功能強大的WAP網絡應用和無限網頁。本章我們將詳細講解WML?Script1.1編程的基礎預法制時,如基本規則、變量預數據類型、操作賦予表達式等。為了敘述上的簡便,以后我們將“WML?Script1.1”簡稱“WMLScript?薄?
4.1?WML?程序中調用WML?Script函數
經過前兩章的學習,熟悉C語言的讀者可能會認識到,WML?的函數功能、邏輯運算功能等都是十分有限的。而WMLScript提供了豐富的函數功能,我們在WAP應用開發可以使用WMLScript來增強WML編程。因此,WMLScript成為擴展WML編程能力的主要開發工具。
4.2?WMLScript的主要優點及其字節碼解釋器
WMLScript具有一套定義好的字節碼和一個解釋器參考結構。無線網絡傳輸中WMLScript的數據均以二進制格式進行傳輸,所以,用戶可以使用乍帶寬通信信道,從而能夠保持客戶端手機只需要最小限度的內存。ECMAScript修改后得到的WMLScript能夠更快、更小、更容易的編譯程序為字節碼形式。所有這些特點,是WMLScript具備了WML所不能具備的很多優點和功能。
4.2.1?使用WMLScript的主要優點
WMLScript的設計宗旨是為WMLScript系統提供一般的腳本處理能力,使用WMLScript我們可以進一步補充基于XML的WML語言的編程功能,開發針對乍帶寬的網絡應用及內容,如文本、圖像、選擇列表等,我們可以使用簡單的格式編寫出更靈活和更具可讀性的用戶界面。WMLScript具備的WML所不能具備的優點和功能,主要包括如下幾個方面:?(1)檢查用戶輸入的合法性:
(2)擴展用戶瀏覽器的功能,比如允許程序員開發手機的電話呼叫、發送短信息、存儲電話號碼、管理電話簿或SIM卡等;
(3)生成用戶端的確認、提示、警告信息或操作對話框,并使之快速顯示在瀏覽器上;
(4)在用戶瀏覽器的更改后,能夠對瀏覽器端的軟件和參數進行擴展與配置;
(5)最大程度克服客戶端的乍帶寬通信連接限制,并提供豐富的程序功能;
(6)補充WML并使之實現針對微型移動終端設備的多種服務,如支持高級用戶界面、增加客戶端智能型、提供用戶瀏覽器外圍功能的訪問能力,以及在服務器與客戶端瀏覽傳輸數據是減少帶寬占用等。
4.2.2?WMLScript的字節碼解釋器
在WMLScript的字節碼解釋器解釋之前,WMLScript語言編寫的文本格式的程序將被首先編譯為二進制格式的代碼。編譯時,編譯器通常先將WMLScript程序分成若干個編輯單位,每個單位的程序都包含一定數量的語句行和WMLScript函數,然后,WMLScript的編譯器將按照這些編譯單位,逐一將WMLScript程序作為輸入內容,而把對應的字節碼作為輸出內容。當用戶通過WAP手機調用WMLScript程序時,編譯器的編碼功能即被激活、執行。
4.3?WMLScript基本規則
WMLScript在許多基本規則方面沿用了WML的做法。不過,由于WMLScript是以C語言為藍本而指定的,所以它的語法特征和C語言非常相像。如果大家對C語言比較熟悉,那么學習和掌握這部分內容應當是比較容易的。
4.3.1?WMLScript與URL
與WML一樣,WMLScript也沿用了WWW和HTML訪問資源的URL、HTTP等規范,并擴大了URL使用的范圍。在WMLScript中,不僅超鏈接、文件路徑即文件名可以作為URL處理,外部函數、訪問控制信息等也可以作為URL處理。
為此,WMLScript采用了WML的變通方法,即改進HTML命名資源為值的方式,采用程序段錨點(Fragment?Anchor)的形式來處理資源定位。程序段錨點根據文檔URL規則進行定義,并按照程序段標識符前加井字號(#)的方式書寫。使用程序段錨點,WMLScript程序可以在WMLScript編譯單位內可任意指定的函數,并可在調用該函數的同時傳遞所需的參數。
4.3.2?詞法結構
WMLScript編程中的詞法結構并不復雜,我們下面就從大小寫敏感、空格、換行、注釋即保留字等方面講解相關的具體規則。
(1)內容類型。WMLScript的內容類型主要針對文件形式和二進制形式兩種情況,類型結構可以在服務器端進行指定,具體形式為:
文本形式:text/vnd.wap.wmlscript;
二進制形式:application/vnd.wap.wmlscriptc。
具體指定方法我們在第4章已經介紹過,這里不再重述。
(2)大小寫敏感。WMLScript1.1是一種大小寫敏感的腳本語言。它所設計的各種關鍵字、變量和函數名都必須合理的使用大小寫。
(3)空格和換行。一般情況下,WMLScript程序值形式將忽略所有的空格、制表符合換行符等。但如果把這些特殊字符通過代碼進行表述,或者作為字符串進行處理時,WMLScript將不再忽略它們。了如,字符串\"Oct?28,2001\"中含有空格,該空格在執行時就不會被忽略,它與不含空格的字符串\"Oct28,2001\"是不同的。
(4)注釋。與WML編程一樣,在WMLScript腳本程序中也可以加入注釋內容。注釋內容不被程序執行,且注釋不能嵌套。WMLScript的注釋方法有兩種:
其一,行注釋。即使用雙斜行號(//)引導以一行內容,這一行內容全部作為注釋內容。如:
//這是以行注釋,由雙斜杠號開始到結束都是注釋。
其二,塊選擇。即以符號“/*”開始,而以符號“/*”結束的期間所有內容都是注釋內容。如:
/*這就是塊注釋,加在中間的內容就是注釋內容*/
(5)數據類型與直接編碼。WMLScript允許將4種類型的數據直接編碼并可嵌套并可嵌如在程序之中。直接編碼的4中數據類型為:整數、浮點數、字符串和布爾值。另外,“無效性”值也可直接編碼”?1.?整數。當以十進制、十六進制或八進制方式使用整數時,可對這類整數進行直接編碼。
編程序時,十進制的數字均不以0開頭,只包含0~9的數值串;十六進制的數據以OX或者Ox開頭,只包含0~9、a~f或者A~F的字符串;八進制的數均以0開頭,只包含0~7的數字串。
2.浮點數。浮點數通常定義為含有小數點的數字,可以包含小數和指數部分。浮點數的形式較多,可以使十進制的整數或浮點數,可以是分數,也可以是指數;但一個浮點數必須至少有一個數。
指數是以e或E開頭,后面跟著一個整數。指數是以10為底冪。例如:e0時10的零次冪,例如:e0時10的另次冪,e-2時10的負2次冪集等于0.01。指數可以帶符號,正好(+)或者減號(-),它們分別代表是正指數和負指數。
3.字符串。字符串是指定義在成對的雙引號(\"\")或單引號(‘?’)之間的內容。
由于WMLScript只允許使用成對的雙引號或但引號來定義字符串,所以程序中使用一個單引號或一個雙引號時就會出現編譯錯誤。
考慮到有些特殊字符不能在字符串中直接顯現出來,所以WMLScript提供了轉譯序列來表示這些特殊字符。
4.布爾型。它只是ture和false兩個數值,用于表示WMLScript中的“真值”或“假值”。布爾型數據可參與異、或等運算,具體規則我們后面介紹。
5.無效型。也稱為“空類型”,它是WMLScript支持的一個表示無效值的量,以invalid表示。該兩與C語言中的NULL類似。
4.保留字。WMLScript中定義有一個保留字集合,含有一些表示特殊意義的單詞這些次不能另外定義,也不能最為其他標識符。WMLScript中的保留字如下:
acces?http?agent?if?break?isvalid?continue?meta?header
div?name?div=?path?domain?return?else?typeof?while
equiv?url?extern?use?for?user?function?var
另外,WMLScript還為將來的版本預留了一些保留字,主要有:
case?finally?catch?import?class?private?const?public?debugger
sizeof?default?struct?do?super?enum?switch?export?throw
extends?try
WMLScript還有一些沒有使用的保留字:
delete?null?in?this?lib?void?new?with
7.標識符。WMLScript的標識符可以指定或命名3種元素:變量、函數和標注。標識符不能以數字開頭,但能一段下劃線(-)開頭,而且,標識符不能是WMLScript的保留字。例如,timeOfDay、speed?、quality、HOME_ADDRESS、_myName、__、varO等都是合法的標識符;而以數字或非短下劃線的特殊符號開頭的字串,以及保留字等都屬于不合法的標志賦,如while、for、if、my~name、$sys、123、3piecs、take.this等。
由于WMLScript是嚴格區分大小寫的,所以字母相同但大小寫不同的標識符不是同一個標識,例如,Work和work就是不同的標識符。
8.名稱空間。WMLScript提供了比較自由的名稱空間,同一標識符可以同時用作不同的目的。例如,作為某一函數名稱的標識符,還可以同時用作變量名、函數參數、程序標注等,使用時他們的屬性或值等并不相互影響。在下面的簡單的例程中,myTest這一標識符即用作了函數名,又用作了變量名、函數參數名、函數參數名、常量名。顯然,WMLScript的這一特定為我們編寫程序提供了很大的方便。
4.3.3?WMLScript程序的基本書寫規則
WMLScript程序的基本書本寫規則:
1.程序由若干語句或函數組成,函數有由若干語句組成;
2.每個完整的語句后面必須加上分號(;),語句關鍵詞語操作數之間必須有空間;分號(;)是WMLScript程序的組成部分;
3.函數體之間必須使用成對的花括號({?})括起來,而且函數結束時在右花括號(})的后面還要加上分號(;);函數說明部分,如函數名、函數類型、函數參數等要放在花括號({})的前面;
4.有些語句可能也需要實用花括號({?})辦含內容,這類語句通常也可以放在函數中,所以花括號({?})是可以嵌套的。
當然,不同的語句、參數、變量等元素在聲明和書寫時可能還有一些更細的要求,具體我們后面介紹這些元素是再專門給出,
4.4?變量與數據類型
變量即數據類型是所有編程語言的概念和組成部分,WMLScript對此也不例外。它對其變量使用方法和數據類型定義方法給出了詳細的規定。變量通常與某數據之相對應,我們可以給變量賦值,并可在程序執行中改變變量的值。下面我們講解WMLScript有關變量與數據類型的詳細規定。
4.4.1變量及其聲明
變量是在WMLScript腳本程序中具有值的符號名,或說標識符。使用變量可以存儲和改變程序中需要的數據。與C語言不同的是,WMLScript僅支持函數內定義的變量或用于傳送數的參變量。
變量使用前必須進行聲明,也就是定義變量,即指定變量的名字。聲明變量的關鍵字是var,它的后面根上作為變量名的合法的標識符,并于最后加上分號(;),即完成一個量的聲明。聲明變量是可以使用var一次聲明多個變量名,相鄰變量之間使用都號(,)間隔。
一般情況下,我們在給變量命名的時候,都希望能夠使用有意義的變量名。例如,當需要使用一個變量表示一本書的價格時,雖然將變量命名為j或book都沒有什么錯誤,但若能命名為bookPrice則會是的WMLScript腳本程序具有更好的可讀性,可以方便編程人員進行腳本的編寫和調試工作。而且,由于WMLScript在給變量命名是不能使用保留字,所以考慮到避免由于一時的疏忽時變量名欲保留字發生沖突,我們建議使用多個單詞組合在以其作為一個變量的名稱,這是一個比較好的解決辦法。例如,如果要定義一個變量來存儲的、一本書的價格,那我們可以不妨使用bookPrice或者book_price作為變量的名稱,這樣,一方面可以時變量顯得更加清晰,另一方面也可以避免變量與保留字的沖突問題。
以上只是我們對于變量命名的建議,并不是強制性的要求,用戶完全可以不按照我們的要求來做,只要遵守WMLScript對于標識符命名的要求就可以了,但養成良好的編程風格不論是對編程人員還是對腳本編寫人員來說,都是十分有意義的。
4.4.2?變量的作用域與生命期
一個變量的作用域是指在程序中能夠引用這個變量的一段代碼。由于WMLScript僅支持函數內定義的變量,所以WMLScript變量的作用與通常就是定義它們的那個函數。在該函數之外,變量不再發揮直接作用。
變量的生命起始值從變量聲明開始到失效為止。變量的生命期也被稱為變量的持久期、存活期。一個變量在定義它的整個函數內都是有效的,函數內的任何語句塊都不會削減變量的生命期或限制變量的作用域。
如果一個變量未經生命就直接使用,或聲明過后再次聲明,都會破壞變量的生命期。前一種情況會導致變量沒有開始聲明期,即沒有“生命”;而后一種情況則導致變量聲明期沒有結束以前就重新賦予聲明期,即讓它多次“降生”。這都會導致變量無效使用。下面函數中的變量使用就說明了這一問題:
function?foo(){
x=1;//錯誤:變量使用前沒有聲明,改變量還沒有“聲明”。
var?x,y,z;
y=x+3;
var?zd?=invalid
if(x){
var(y);//錯誤:這一變量已經聲明,這里是重復聲明。
};
};
4.4.3?變量的使用
WMLScript的變量只能在定義它的函數內使用。使用時需要聲明變量,聲明變量是可以同時對變量賦值,甚至對變量進行運算。例如,下面的簡單函數就說明了變量的這種靈活的使用方法:
function?ourAge(){
var?myAge=38;
var?yourAge=26;
var?ourAge=myAge+yourAge;
return?ourAge;
};
使用變量時可通過調用變量名字的形式來實現。上面例子中的“var?ourAge=myAge+yourAge;”一句,通過調用變量名,變量ourAge對變量myAge和變量yourAge實行了求和操作。
4.4.4?變量類型與數據類型
WMLScript是一種“弱類型”的語言,及其變量沒有確定的類型。WMLScript變量的類型有改變量所賦數據的類型決定,并根據數據類型的改變而改變。WMLScript只支持內部定義的數據,因此我們編寫程序是無需指定WMLScript變量的類型,WMLScript減根據變量而賦數據的類型自動進行匹配。由于WMLScript的數據類型共有整數、浮點數、字符串、布爾型和“無效型”五種類型,所以WMLScript變量的類型所能匹配的也就是這五種類型。
4.4.5?變量值域
由于變量類型尤其所賦數據的類型決定,所以變量值與域其所賦數據的可取范圍等價的。下面的我們就給出整數、浮點數、字符串和布爾型的區值范圍,以參照確定應類型變量的值域。?1.整數的范圍。WMLScript支持的整數是32位的,也就是說整數的區值范圍是從2147483648到+2147483647。我們可以在程序運行期是用Lang函數來取得這些值,如:
Lang.maxInt();?//獲取最大的整數
Lang.maxInt();?//獲取最小的整數
2.浮點數的范圍。它是指WMLScript浮點數的精度所能表示的最小和最大數值WMLScript支持32為的單精度浮點數,其最大至時3.40282347E+38,最小的非零的數是1.17549435E-38或更小(按照正常的精度)。
我們可以使用浮點Float函數庫在程序運行其取得這些數值:
Float.maxFloa();?//獲得WMLScript所支持的最大浮點值
Float.maxFloa();?//獲得WMLScript所支持的最小浮點值
對于運行期出現的一些特殊的浮點數,WMLscript將按照下述規則處理:
其一,如果操作結果是一個不能被單精度浮點數所能表示的數值,那么該結果將被認為是invalid,即無效值;
其二,如果操作結果發生下溢出,那么結果將作為0.0處理:
其三,負的零和正的零是完全相等的。
3.字符串的范圍。任何由于字母、數字或特殊字符組成的符號串都是WMLScript中定義的有關字符串的操作或String庫中的函數控制字符串。
4.布爾型數據的范圍。布爾型數據只有ture和flase兩個取值,這也是布爾型變量的兩種數值。我們可以使用布爾型數據取初始化或指定某一變量的數值,或將布爾值變量寫入一個需要布爾值作為參數的語句。布爾值可以是數值運算的結果,也可以是邏輯運算的結果。
下面就是定義布爾型變量并賦初值的例句:
var?truth=truth;
var?lie=!truth;
4.5?操作符與表達式
在WMLScript中,表達式可以把變量、常量與操作符結合起來,經過運算能夠產生一定的運算結果。表達式運算后產生的結果可以是整數型、浮點數型、字符串型或布爾型的數據。其實,對于表達式我們并不陌生,例如,1+2就是一個簡單的表達式。
WMLScript的表達式主要有兩種類型。一種是賦值表達式,即把數據賦給變量的一種表達式,例如,myBook=3,在這個表達式中,將3?賦給變量myBook,同時,這個表達式本身也有一個運算結果,那就是3。另外一種是運算表達式,它是指產生一個運算結果而不進行賦值操作的表達式,例如1+2就是一個運算表達式,在這個表達式運算產生的結果是3,?但這個表達式并沒有把運算結果賦給變量。
在表達式運算的過程中,表達式中操作一個或這兩個數據產生運算的符號做操作符,被操作符操作的數據稱作操作數,在WMLScript中我們會使用到各種操作符,下面就對操作符及有關的表達式進行詳細講解。
4.5.1?賦值操作符
賦值操作符用于賦值操作,即給變量指定所需的數值,它能把有操作數的運算結果給做操作數,最簡單的賦值操作符就是“=”,例如x=2,就是將2賦值給變量x。在如以下幾行語句都是賦值操作:
var=\"abc\";
var?b=a;
b=\"def\";
賦值操作符不需要指定使用對象,也不會改變賦值操作符右邊變量的數值。WMLScript的賦值操作符主要包括以下幾種:
1.=。用于賦值操作,將有操作數賦給左操作。
2?+=。將有操作數與左操作數進行相見運算,然后把運算結果賦值給左操作數。例如,假設x=3,那么x+=2運算后的結果為x=5。
+=是比較特別的操作符,因為它可以將兩個字符串相連,所以+=操作符也可以對字符串進行操作,然后將連接后的字符串賦給左操作數。例如,假設x=\"Happy\",那么x+=\"new?Year\"運算后結果是x=\"Happy?New?Year\"。
3.-=。將左操作數簡取有操作數,然后把運算結果賦值給左操作數。例如,假設x=3那么x-=運算后的結果為x=1。
4*=。將左操作屬于有操作符進行相乘運算,然后把運算結果賦值給左操作數。例如,假設x=6,那么x*=2運算后的結果為x=6。
5/=。將右操作屬于右操作符進行相乘運算,然后把運算結果賦值給左操作數。例如,假設x=6,那么x*=2運算后的結果為x=6。
6div=。擁有操作數處理左操作數,然后把運算結果中的整數部分賦值給左操作數,例如x=7,那么xdiv=2運算后的結果為x=3。
7%=。功能是求余數并賦值,用右操作數除以做操作數,最后把運算得到的余數值給操作數。例如,假設x=7,那么x%=3運算后的結果為x=1。
8<<=。功能是帶符號左位移并賦值,即將左操作和右操作數進行左位移操作,在將結果賦給左操作數。
9>>=。可將左操作和右操作進行右操作進行補零右位移操作,在將結果賦給左操作數。
4.5.2?數學運算操作符
數學運算操作符可以對數值類型的操作數進行運算,然后返回一個數值類型的運算結果。
1+。這是加運算操作等,它對應著數學運算中的加法運算,例如表達式1+2的運算結果為3。
加操作符還可以對字符串類型的操作數進行運算,然后將兩個字符串相連起來作為運算
2-?。即檢操作符,對應著速學運算中的減法運算,例如表達式2-1的運算結果為1。
同時,“-”還是一個取負操作符,當它作為取負操作符的是一個操作數,取負操作符的功能使返回操作數的相反數。
3*。這是乘操作符,它對應著數學運算中的乘法運算,例如表達式2*3的運算結果為6。
4/。即除操作符,對應著數學運算中的除法運算,但WMLScript中的除法運算有些特別,在WMLScript中,除法運算后的結果是一個浮點數,而不想C語言或者Java語言那樣在整數進行除法運算式井運算結果強行轉化整數。在WMLScript中,1/2=0.5,而在Jave中,1/2=0。
5div。這是整除操作符,對應著數學運算中的整數運算,運算后的結果一個整數,這一點與C語言或者Java語言中的情況是一樣的,可以在整數進行除法運算式將運算結果強行轉換整數。
6%。即取模操作符,它對應著數學運算中的取莫運算,也就是將兩個操作相除,返回相除后的余數。
取模操作符主要用于判斷一個數字是否能被另一個數字整除。
((the?Year%3==0))&&(the?Year%100!=0))||(the?Year%400==0)
其中&&代表的是邏輯運算中的與運算,||代表的是邏輯運算中的或運算,關于邏輯運算,我們后面會詳細介紹。
7++。這是遞增操作符,它只有一個操作數,操作可以在操作符的左邊,也可以在操作符的右邊,它所完成的運算操作是將操作數加1。假設操作數名稱為j,值為2,那么++j加1,然后返回j的值3;而j++則實現返回j的值2,然后將j加1。
在循環中,我們常常會用到遞增操作符的作用正好相反。遞減操作完成的運算操作是經操作數減1。例如,假設操作數名稱為j,值為2,那么--j先將j減1,然后返回的值1;而j--是先返回j的值2,然后將j減1。
4.5.3?位操作符
為操作符在運算實現將操作轉化32位的二進制數,然后對每個操作數分別按位進行運算,運算后在將二進制的結果按照標準WMLScript數值類型返回運算結束。
1&。這是為與操作符,它可以對兩個操作數按位進行于操作,其運算規則是:
0&0=0,0&1=0,1&0=0,1&1=1
2|。這是位或操作符,它可以對兩個操作數按位進行或操作,運算規則是:
0|0=0?,0|1=1,1|0=1,1|1=1
3^。這是唯一或操作符,它可以對兩個操作按位進行異或操作,其運算規則是:0^0=0,0^1=1,1^0=1,1^1=0
4~。這是位非操作符,它只有一個操作數,可對操作數按位進行非操作,運算規則是:~0=1,~=0
5<<。這是左移操作,它可以對左操作數進行向左一位的操作,由操作數給定了要移動的位數,在移動過程中,左操作數的最低為補充0。
6>>。這是右移操作符,它可以對左操作數進行向右移位的操作,由操作數給定要移動的位數,在移位的過程中,丟棄向右移的位。
7>>>。這是填0右移操作符,它與右移操作符相似。當對證正數進行操作時,它們的效果完全相同;不同之處在于,當進行負整數右移操作時,因為負責轉化為二進制后,最高為1,所以在進行右移操作后,最高位仍然補充1,而在進行填0右移操作時,最高為補充的是0,因此,這是負數將轉化為正數。
4.5.4?邏輯操作符
邏輯操作符可以將布爾類型的表達式組合起來,完成邏輯運算操作,然后返回邏輯運算的結果--真或假,這樣就可以完成比較復雜的邏輯判斷工作。邏輯操作共有3種;
1&&。即邏輯與操作符它只有在兩個操作數都為ture的時候,返回結果為ture,在其他情況下,返回結果為false或者invalid。
2||。這是或操作符,它在兩個操作數至少有一個為ture的時候,返回結果為ture,在其他情況下,返回結果為false或者invalid。
3!。即非操作符,它只有一個操作數。當操作數為ture時,返回結果為flase;返回結果為ture.
4.5.5?比較操作符
比較操作符可以把操作數進行比較,然后返回一個邏輯值,表明這個比較操作的結果是否為真。比較操作的操作數可以是數值類型或者字符串類型的數據。比較操作符也常被稱為關系運算符。
WMLScript支持的比較操作符共有6種,下面被介紹一下。
1.?==。即等于操作符,它可以比較兩個操作數是否相等。如果兩個操作數相等,則返回ture,否則返回false
2.?!=。即不等操作符。它可以比較兩個操作數是否相等。如果兩個操作數相等,則返回false,否則返回ture。
3.?>。即大于操作等。其運算規則時,如果左操作數大于右操作數,則返回ture。
posted @
2006-04-29 09:44 崛起的程序員 閱讀(187) |
評論 (0) |
編輯 收藏
元素和標簽是WML的主要語法,它們決定了WML編程的基本原則。本章我們將從WML的元素、標簽、屬性等方面詳細講解WML的編程方法。學習本章知識之前,讀者應當了解WML元素與標簽的區別。WML的元素通常有一個首標簽、內容、其它元素及一個尾標簽組成。也就說,單獨的標簽是一個元素,成對出現的標簽與其包含的內容也構成一個元素。由于元素牽涉及標簽,標簽又涉及屬性。?
3.1?卡片、卡片組及其屬性
我們前面介紹了WML的卡片與卡片組,主要從概念和相互關系的角度進行了分析。我們這里則從卡片、卡片組的組成、相關元素、標簽技術性等編程角度進行分析和講解。?3.1.1?共有屬性
WML元素的共有屬性主要有3個:id、class和xml:lang屬性。
WML的所有元素都有兩個核心屬性,即標示(id)和類(class)屬性。它們主要用于服務器方的信息傳輸。其中,id屬性用于定義元素在卡片組中的唯一標示,即它的名稱;class屬性用于給當前元素定義一個或更多的類(class)。與卡片組一樣,類(class)也是有名字的,而且多個元素可以使用一個類(class)名。具有相同類名的單一卡片組中的所有元素均可被看作相同類的一個部分。類名是區分大小寫的。如果在class屬性列表中,一個元素多個唯一的類名,那么該元素可以看作這些類中的一部分。具有同一屬性的多個類名必須用兩個以上的空格間隔,WML程序執行時將忽視其中多余的類名及其屬性。
另外,在WML程序,所有包含文本的元素均具有“xml:lang”屬性。該屬性用于指定當前元素及其屬性所用的描述語言,如英國英語、美國英語、法語、德語等,并可以為用戶瀏覽器選擇顯示文本的語言提供依據。
3.1.2?WML程序的文件頭
合法的WML卡片組均屬合法的WML文件,因此它必須包含WML的聲明及文件類型的聲明。典型的WML程序的文件頭包括我們前面多次提到的以下兩行程序:
<?xml?version=\"1.0\"?>
<!DOCTYPE?wml?PUBLIC?\"-//wapforun//DTD?WML?1.1//EN\"?\"http://www.wapforum.org/DTD/wml_1.1.xml\">
編寫WML程序時,我們必須寫入這兩行程序,并放在程序的開始處。其中\"-//wapforun//DTD?WML?1.1//EN\"是標準通用標記語言SGML的公共標示;\"http://www.wapforum.org/DTD/wml_1.1.xml\"是WML程序文檔類型的標示。文檔類型標示也可以是\"text/vnd.wap.wml\"或“application/vnd.wap.wmlc”,其中前者制定WML的原文類型,后者貧╓ML程序編譯后代碼類型。
3.1.3?WML元素
WML的WML元素用于定義一個卡片組,并通過<wml>與</wml>標簽包含和封裝該卡片組中的所有卡片及信息。它的語法格式如下:
<wml?xml:lang=\"lang\">
內容(content)
</wml>
其中xml:lang=\"lang\"用于指定文檔所用語言(前面已有介紹),語言\"lang\"的值屬于NMTOKEN型數據。
wml元素中包含的內容(content)中除了文本、圖像等信息之外,還可以包含head、template及card元素。其中head、template元素如果包含的話則只可包含一次,而card元素必須至少包含一次。有關這些元素的用法我們后面介紹。
3.1.4?template元素
template元素用于為當前卡片組中的所有卡片定義一個模板,同一規定卡片的某些參數。模版中的事件處理功能則可將這些參數自動應用于同一卡片組中的所有卡片。不過,我們也可以是其中某個或某幾個卡片不采用模板規定的形式,方法是在該卡片中定義一個同名的事件來替代模板塊中相應的事件。template元素通過<template>和</template>標簽含所需內容(content)而實現模板功能的,其語法格式如下:
<template?oneterforward=\"href\"?onenterbackwared=\"href\"?ontimer=\"href\">
內容(content)
</template>
template元素包含的內容中,除了卡片的一般參數外,還可以包含任意多次的do元素和onevent元素。template元素屬性的功能及用法說明如下:
1)oneterforward。當用戶在瀏覽器中進入當前卡片時,該屬性將指定超鏈(href)的URL地址,瀏覽器將據此打開URL指定的卡片或事件。
2)oneterbackward。與上一屬性類似,該屬性也可以指定其相應卡片或事件的URL地址。如果用戶瀏覽時執行prev任務,那么瀏覽器就會定位到該屬性所指定超鏈(href)的URL地址,并打開URL指定的卡片或事件。
3)ontimer。當指定時間timer過期的時候,用戶瀏覽器就根據ontimer屬性指定的URL打開相應的卡片。
3.1.5?card元素
WML的卡片組是由一個或多個卡片(card)構成的,每個卡片都包含有一套用戶和瀏覽器交互操作的配置及模式。用戶對交互操作的需求是多樣性的,所以卡片定義時也必須是多樣性的。為此,WML提供了card元素,通過<card>和</card>標簽定義一個卡片的各種屬性、包含內容。它的語法格式如下:
<card?id=\"name\"?title=\"label\"?newcontext=\"boolean\"?ordered=\"true\"?onenterforward=\"href\"?onenterbackward=\"href\"?ontimer=\"href\">
內容(content)
</card>
card元素中包含的內容(content)中除了文本、圖像信息之外,還可以包含onevent、timer、do和p元素。其中,timer元素只可使用一次,其余3種可使用多次。而且,如果card元素包含onevent元素或timer元素的話,那么onevent元素必須放在最前面,timer元素放在onevent元素的后面,隨后才可以使用do或p元素。這個優先順序是不能亂的。
card元素屬性的功能及用法介紹如下:
1)id。用于指定card的名字。改名字是程序導航定位的依據,可以用作程序段錨點,比如<go?href=\"#cardname\"/>。其中的cardname便是由id指定的卡片名。
2)title。用于為卡片制訂一個簡單的標題或說明信息。
3)newcontext。用于指定WAP手機瀏覽當用戶重新進入的時候是否需要初始化卡片中所有的內容。它有true和false兩種選擇,當指定newcontext=\"ture\"時,卡片的所有內容在用戶重新進入時將進行初始化,也不清除歷史紀錄;否則,指定newcontext=\"false\"時,將不進行初始化設置,也不清除歷史紀錄。默認狀態下的設置值為false。另外,newcontext僅當作為go任務的一部分時才可被執行。
4)ordered。用于向用戶手機的瀏覽器指明卡片內容的組織形式,以便讓瀏覽器根據自身特點及卡片內容組織及時安排顯示布局。它有兩種布爾值得設置,即true和false。
當ordered=\"true\"時,瀏覽器將按照線性順序顯示卡片各區域的內容。這個線性順序通常是大多數用戶所習慣采用的信息瀏覽順序,比如發送E-mail信息時,我們依次需要E-mail首件人地址、主題及E-mail內容,這個邏輯順序就數線性順序。
當ordered=\"flase\"時,瀏覽器將根據用戶選擇或指定的順序來顯示內容。這種情況主要是用于顯示用戶選項、無序組建或用戶輸入的簡單數據紀錄等。
5)onenterforward。onenterforward事件僅當用戶使用go任務或類似于go的任務位和瀏覽卡片時才可發生,即如果用戶執行go任務,則瀏覽器就會定位<go>標簽中指定超鏈(href)的URL指定的卡片。card元素中的onenterforward屬性是onevent元素的一個簡單格式,用于直接指定onenterforward事件的URL地址。
6)onenterbackward。該屬性可以指定其響應時間的URL地址。如果用戶瀏覽時執行prev任務,那么瀏覽器就會定位到該屬性所制定超鏈?(href)的URL地址,并打開URL指定的卡片。onenterbackward屬性也屬于onevent元素的一個簡單格式。
7)ontimer。當指定時間timer過期的時候,用戶瀏覽器就根據ontimer屬性指定的URL打開相應的卡片。它也屬于onevent元素的一個簡單格式。
3.1.7?access元素
access元素是由一個單獨的的標簽<access>標簽實現的元素。用于定義WML整個卡片組的操作權限,即訪問控制參數。access元素必須在head元素內和其它的meta信息一起聲明,而且每個卡片組只能有一個access元素。其語法格式如下:
<head>
<access?domain=\"domain\"?path=\"path\">
...
</head>
access元素屬性的功能及用法如下:
1)domain。用于指定對卡片組進行操作的URL域,默認域是當前卡片組所在的域。domain的目的是限制訪問,用戶瀏覽時瀏覽器將根據domain值所規定的值來得出與值匹配的地址,并訪問該地址對應的卡片或事件。?2)path。用于指定卡片組操作的其它卡片組所在的根目錄。默認目錄是“/”,即當前卡片組所在的根目錄。默認目錄的規定使得所有在domain域下的卡片組都可以操作當前卡片組。path的值是訪問時需要匹配的路徑,它的工作原理與domain十分相似,需要與路徑的每個子路徑相匹配,否則均屬無效。
3.1.8?meta元素
meta元素用于定義WML卡片組相關的通用meta信息。該元素是由一個單獨的標簽即<meta/>標簽實現的元素,其語法格式如下:
<meta?name=\"name\"|http-equiv=\"name\"?content=\"value\"?forua=\"true|false\"?scheme=\"format\"/>
其中,name屬性和http-equiv屬性只能選擇使用一個;content屬性是必選的,其值根據屬性而定;scheme屬性目前尚不支持;forua屬性為可選屬性。各屬性功能及用法說明如下:
1)content。該屬性用于指定meta信息的性質的值,是不必選的。
2)name。用于指定meta信息性質的名稱。用戶瀏覽器通常忽略已經命名meta數據,網絡服務企業拒絕發送包含該屬性所指定meta數據名稱的內容。
3)http-equiv。該屬性用于替代name屬性,可將meta數據轉為WSP或HTTP協議的響應頭。
4)forua。該屬性用于指定那些開發者希望傳送值用戶瀏覽器的性質。它有ture和fales兩個取值,如果取false,則卡片組在發送往客戶端以前必須用中間代理去除meta元素信息,這是因為傳輸的協議可能改變;若取值為true,則meta數據必須如實送往用戶的瀏覽器。默認的狀態下,該屬性的值為false。
5)scheme。該屬性用于指定解釋meta信息性質值的形式或結構。具體的形式或結構因meta數據的類型不同而不同。
3.2?任務及其元素
WML允許我們在程序中指定一些任務,當某些特定的事件激活時,即可執行這些任務,從而完成需要的操作。例如,我們可以設定任務,當用戶按下相應的功能鍵時,瀏覽器就可以打開指定的卡片組或卡片。目前,WML提供了4個任務元素,即go、prev、noop和refresh,它們主要與do元素和onevent元素中指定的事件相響應。本節我們就對任務的這些元素做一詳細介紹。
3.2.1?go任務
go任務是通過go元素來聲明的,而go元素是通過<go>和<go/>標簽進行定義的。go元素主要用來定義瀏覽器需要導航的URL地址。如果該地址是一個WML卡片或卡片組的名字,則瀏覽器就會打開并顯示相應的卡片、卡片組;否則,瀏覽器就會執行該URL指定的任務或事件等。在歷史推棧中,go任務執行的是一個“推進(push)”操作,也就是說,它執行時瀏覽器瀏覽的URL地址將送入歷史紀錄列表中,以被它用。
go元素中可以包含任意次的setvar元素或postfield元素。postfield元素前面已有介紹,這里不再重述,setvar元素我們后面介紹。
go任務的語法格式如下:
<go?href=\"href\"?sendreferer=\"false|true\"?method=\"get|post\"?accept-charset=\"charset\">
內容(context)
<go/>
其中屬性的功能及用法介紹如下:
1)href。該屬性用于指定目標URL地址,比如讓瀏覽器顯示的卡片的地址即名稱等。屬性是必選的,其它屬性為可選。
2)sendreferer。該屬性用于指定是否傳遞調用href所指定的URL的卡片的URL,也是當前頁的URL,即HTTP頭中HTTP_REFERER。有兩種選擇:true或false。其中,默認值為false。
3)method。與HTML中的表單FORM的method屬性一樣,該屬性用于指定表單是以GET的方式還是post的方式遞交,以便通用網關接口CGI處理。默認值為get,但如果沒有指定method屬性,而<go>和<go/>之間存在postfield元素,則WAP手機瀏覽器會自動以post方式傳遞。
4)accept-charset。當web服務器處理來自瀏覽器的輸入信息時,該屬性可指定服務器進行數據編碼時必須采用的字符集列表。也就是說,該屬性指定的字符集替代HTTP頭里指定的字符集,以便作為服務器選用字符集的標準。
3.2.2?prev任務
prev任務是由prev元素實現的。該元素通常是一個單獨的標簽<prve/>,不過有時也可由<prev>和</prev>一對標簽進行定義。它用于指定將瀏覽器導航至歷史推棧中的前一個URL地址。在瀏覽器操作的歷史推棧中,prev任務執行的是“取出”操作,將前一個URL地址取出,并把當前URL地址推進歷史推棧。如果歷史推棧中沒有前一個URL地址,即prev/元素不執行任何任務。
prev任務的語法格式為:
<prev/>
或<prev>?內容(content)?</prev>
在后一語法格式中,prev元素包含的內容里面一般是setvar元素,該元素的含義前面已有介紹,這里不再重述,具體的用法隨后介紹。
3.2.3?refresh任務
refresh任務由refresh元素聲明,它用于刷新當前的卡片,對卡片內指定的變量進行更新。其語法格式為:
<refresh>
內容(context)
</refresh>
其中包含的內容(content)中一般有setvar元素,其語法格式為<setvar?name=\"name\"?value=\"value\"/>,它可指定更新的變量名name,即更新的變量值value。另外,refresh元素也可以不包含setvar元素。而通過時間限制(timer元素)對卡片進行刷新。
3.2.4?noop任務
noop任務由noop元素進行聲明,表示什么也不做,是一個空操作,在替代卡片組級的do元素是十分有用。該元素是一個單獨的標簽,即?<noop/>?標簽。其語法格式如下:
<nnop/>
noop元素沒有屬性,下面的簡單程序中就包含了noop元素實現得空任務操作:
<card?id=\"card1\">
<do?type=\"options\"?name=\"dome\">
<noop/>
</do>
...
</card>
3.3?時間及其元素
WML提供了幾個元素,專門用于處理用戶瀏覽器的導航和事件。利用這些元素用戶可以給某任務制定關聯事件。那么當事件觸發時,瀏覽器就會執行相應的任務,比如URL導航就是通過事件實現的。而且,事件可以和一個需要完成的任務捆綁在一起。事件捆綁時一般是通過幾種元素及其標簽聲明來實現的,如go、do和onevent等元素。下面我們就講解WML的事件元素及事件。
3.3.1?do元素
do元素提供了一個通用的事件處理機制,使得用戶可以參與當前卡片的事件處理。通過<do>和</do>標簽將用戶交互和某一個任務聯系在一起。用戶交互可以是用戶按下的功能鍵、選擇的菜單項,也可以是用戶的聲音提示。當用戶激活這些交互功能時,用戶瀏覽器就會執行與do元素相關的任務。其語法格式如下:
<do?type=\"type\"?label=\"label\"?name=\"name\"?optional=\"boolean\">
任務(task)
</do>
其中tast是與do元素關聯的動作,也是條件激活時瀏覽器即將執行的內容。在do元素中,用戶必須綁定且只能綁定go、prev、noop和refresh四種元素所實現任務中的一個任務(task)。go元素用于定位制定的URL地址,prev元素用于定位并打開前一操作或任務,doop為空操作,refresh用于刷新當前卡片組或任務,有關他們的詳細用法我們后面會陸續介紹。
do元素可以用于卡片一級,也可用于卡片組一級。當用于卡片一級時,do元素必須包含在card元素中;而用于卡片組一級時,do元素必須包含在template元素中,由此定義的do元素將同時應用于當前卡片組的所有卡片。此時如果某個卡片不想應用模板中的do元素及其任務,則需采用我們前面介紹的方法,使用同名事件處理來替代模板中的do元素的事件處理。而且,不論事件關聯的任務是否相同,當do元素定義的事件名稱相同時,卡片的do元素將忽視卡片組一級do元素的影響,及卡片一組的do元素將被優先執行。
另外,含有空操作任務的do元素,不論它是否被激活,它都不會傳送或顯示到用戶的瀏覽器中,這在一定程度上可以加快瀏覽器的工作效率,因為服務器端體它拋棄了一些空任務的判斷。?do元素各個屬性的功能及用法講解如下:
1)type。用于指定do元素的類型(type),也即需要關聯、綁定的用戶交互事件,是必選屬性。用戶瀏覽器接到這些事件后,就會激活它們并執行相應的操作與處理。如果在一個卡片中定義了多個do元素并擁有同樣type,那么用戶必須為每個do指定不同的事件名才行,否則就會發生判斷混亂的錯誤。
do元素典型的類型(type)及執行條件介紹如下:
1、accept。當用戶選擇或按下相應功能鍵時(accept)、選項、命名或按鈕時,瀏覽器接收或激活當前所作選擇。?2、prev。激活prev鍵時,瀏覽器將導航到歷史記錄中的前一個卡片。
3、help。激活HELP功能鍵或相應按鈕、命名時,瀏覽器顯示與當前內容相關的幫助信息。
4、reset。激活reset功能鍵或相應按鈕、命名時,清除或重置當前卡片組或瀏覽器的狀態。
5、options。激活options功能鍵或相應按鈕、命名時,瀏覽器顯示與當前內容有關的選項或附加操作。
6、delete。激活delete功能鍵或相應按鈕、命名時,刪除當前項目或選擇。
7、unknown。如果給出的類型不能為do元素所識別,則一律按照unknown型處理,相當于類型為空,即type=\"\"。
8、vnd.*。vnd.*及其它不同大小寫組合[Vv][Nn][Dd].*。這種類型定義的都是vnd.cotype,用于激活供應商或用戶瀏覽器自定義的某個特定功能,其中co為公司(company)名的縮寫。
9、X-*與X-*。擴展類型,目前WML中還沒有使用。
2)label。該屬性指定的文本字符串可以表示用戶的交互事件。例如,當涯騁桓鋈撾癜蠖ㄔ赼ccept鍵上之后,并設置了label屬性,比如label=\"gone\",那么瀏覽器就會將label的值“gome”顯示在屏幕上;如果不指定,瀏覽器則會顯示默認的“ok”字符串。為了保證能在較小的手機上顯示出來,label的屬性值最多不超過6個字符。不過這可能因WAP手機品牌、型號不同而稍有不同,有的手機最多不能超過5個字符。而且,如果手機瀏覽器不支持動態標簽顯示,那么它就會忽視label屬性。
3)該屬性用于指定do元索所綁定事件的名稱。如果多個do元素制定了相同的name,那么他們綁定的事件統屬一個。如果卡片一般與卡片組一級中do元素制定了相同的事件名,那么卡片一級的時間將被優先執行,卡片組一級的事件將被忽視。
WML規定,在同一卡片或在同一模板中,不得指定具有相同事件名(name)的兩個或兩個以上的do元素。
另外,如果name屬性值為空,則相當于沒有指定name屬性,這時do元素執行的事件或操作由type的屬性值決定。
4)optional。指定瀏覽器是否忽視do元素及其包含的任務。有兩個可選值:true和false。如果值為true,則瀏覽器將忽視當前do元素,即不執行它所綁定的任務。反之,若值為false,則執行do元素。
3.3.2?ontimer事件
ontimer用于指定一個事件。當<timer/>?標簽指定的時間到期后,瀏覽器就執行ontimer所指定的這個事件。ontimer的時間可以是一個URL地址,一個卡片組,一個WML網頁,一幅圖像或其他符合URL定位的規則的文件。<timer/>標簽指定的時間為正整數,單位大小為1/10秒。
ontimer時間只能包含在card元素或template元素的標簽中進行定義,其語法形式如下:
<card?id=\"name\"?title=\"label\"?newcontext=\"boolean\"?ordered=\"true\"?onenterforward=\"href\"?onenterbackward=\"href\"?ontimer=\"href\">
內容(content)
</card>
或:
<template?onenterforward=\"href\"?onenterbackward=\"href\"?ontimer=\"href\">
內容(content)
</template>
ontimer事件只有一個屬性,即ontimer。它用于指定一個超鏈(href)的URL地址,指定時間timer過期的時候,用戶瀏覽器就會按照超鏈(href)的URL打開相應的卡片。
3.3.3?onenterforward事件
onenterforward事件僅當用戶使用go任務或類似于go任務的任務來定位和瀏覽卡片時才可發生。設置onenterforward事件后,當用戶進入當前卡片組時,瀏覽器就會定位onenterforward屬性或<go/>標簽中指定超鏈(href)的URL地址,并打開URL指定的卡片。
onenterforward事件需要包含在card元素、template元素或onevent元素的標簽中進行定義,其語法格式為:
<card?id=\"name\"?title=\"label\"?newcontext=\"boolean\"?ordered=\"true\"?onenterforward=\"href\"?onenterbackward=\"href\"?ontimer=\"href\">
內容(content)
</card>
或:
<template?onenterforward=\"href\"?onterbackward=\"href\"?ontimer=\"href\">
內容(content)
</template>
或:
<onevent?type=\"onenterforward\">
<go?href=\"href\"/>其他任務(task)
</onevent>
前兩種格式中,onenterforward事件作為card元素或template元素標簽中的一個屬性進行定義的,該屬性即為onenterforward,它制定了一個超鏈(href)的URL地址,當用戶進入當前卡片時,瀏覽器就據此打開URL指定的卡片。這種格式制定的任務相當與go任務。
3.3.4?onenterbackward事件
當用戶使用prev任務或類似的任務來導航至某一卡片時,onenterbackward事件才可發生。換句話說,當用戶從歷史堆棧中選取URL地址,并通過瀏覽器打開這一地址對應的卡片時,onenterbackward事件才可能發生。
與onenterforward事件類似,onenterbackward事件也需要包含在card元素、template元素或onevent元素的標簽中進行定義。其具體語法格式如下:
<card?id=\"name\"?title=\"label\"?newcontext=\"boolean\"?ordered=\"true\"?onenterforward=\"href\"?onenterbackward=\"href\"?ontimer=\"href\">
內容(content)
</card>
或:
<template?onenterforward=\"href\"?onterbackward=\"href\"?ontimer=\"href\">
內容(content)
</template>
或:
<onevent?type=\"onterbackward\">
<go?href=\"href\"/>其他任務(task)
</onevent>
前兩種格式中,onterbackward事件是作為card元素或template元素標簽中的一個屬性進行定義的,該屬性即為onterbackward,它指定了一個超鏈(href)的URL地址,當用戶使用prev等任務項回到地址時,瀏覽器就會打開URL指定的卡片。
后一種格式中,onterbackward事件作為onevent元素的一給類型值,并結合<go/>標簽指定事件激活時瀏覽器需要打開的卡片的URL地址。
3.3.5?onpick事件
onpick事件在定義時一般通過onpick屬性指定一些項目,當用戶選擇或取消這些項目時,即可觸發onpick事件,執行onpick屬性所指定的項目,如打開卡片、卡片組或其他事件等。onpick事件通常在option元素的標簽中進行定義,其語法格式如下:
<option?value=\"value\"?onpick=\"href\">
內容(content)
</opiton>
可以看出onpick時間作為option元素的一個屬性來定義具體的動作。這個屬性即onpick,它指定了事件觸發時瀏覽器需要定位的超鏈的URL地址。
3.3.6?onevent元素
onevent元素通過<onevent>和</onevent>標簽可以把包含的任務與特定的時間捆綁在一起。當用戶激活這一特定事件時,onevent元素所綁定的任務就會被立即執行。onevent元素的語法格式如下:
<onevent?type=\"type\">
任務(task)
</onevent>
其中task是與onevent元素關聯的動作,也是條件激活時瀏覽器即將執行的內容。與do元素一樣,onevent元素中用戶也必須綁定且只能綁定go、prev、noop和refresh四種元素所實現任務中的一個任務,go元素用于定位指定URL地址、prev元素用于定位并打開前一操作或任務,noop為空操作,refresh用于刷新當前卡片組或任務。
onevent元素只有一個屬性,即type屬性,它是必選屬性,主要用于定義特定事件的名稱。該屬性值的數據類型為CDATA型。
3.3.7?postfield元素
postfield元素用于指定當瀏覽器接到URL請求時,向原服務器(origin?server)傳送的域名其域值。傳輸時,傳輸域及傳輸值的實際編碼方式主要依賴于瀏覽器與原服務器的通信方式。postfield元素是通過單獨?lt;postfield/>標簽進行定義的,其語法格式如下:
<postfield?name=\"name\"?value=\"value\">
它共有兩個屬性:name與value,它們的取值均屬于VDATA型數據。其中,name屬性用于指定傳輸域的名稱,value屬性用于定義傳輸的值。這兩個屬性均為必選屬性。
3.4?變量設置元素與變量設置的有關規定
幾乎所有的WML內容都可通過設置參數來實現,這為我們靈活的開發WML程序提供了方便。本節我們先介紹一個變量設置元素,然后再介紹與變量設置有關的一些具體規定。
3.4.1?setvar元素
setvar元素用于指定在當前上下文內容中的變量的值,從側面影響正在運行的任務。其語法格式如下:?<setvar?name=\"name\"?value=\"value\"/>
它有兩個屬性:name和value。前者用于指定變量的名稱,后者用于指定所需賦給變量的值。這兩個屬性都是必選的,它們的數據類型均屬于VDATA型。如果name屬性所規定的變量名不合法或不符合運行環境的要求,那么setvar元素在WML程序運行中將被忽視,不能發揮其應有的作用。
3.4.2?變量設置
WML編程中可以使用變量,變量使用前必須進行定義。變量的命名原則及定義方法我們上一章已經講過了,這里不再重述。在這里,我們主要介紹WML程序中設置變量的規定。
如前所述,setvar元素可用來設置變量,設置時setvar元素一般需要在go、prev或refresh元素中進行定義。另外,利用input和select元素也可以設置變量。其中前者是將用戶輸入的文本賦給變量,作為變量的值;而后者則將用戶從option元素中選擇的value屬性的值賦給變量。有關input元素和select元素的語法格式及具體用法我們后面再行介紹。
設置變量時,以下幾種情況還應當引起大家注意:
1)可以使用WMLScript的變量值設置WML的變量,反之亦然。也就是說,使用WML及WMLScript編寫程序時,它們可以使用同名編程。
2)在WAP開發工具中,通常提供有對變量進行管理和維護的選項卡或對話框,開發人員從中也可以對相應的變量進行設置及編輯。
3)在當前上下文內容中,可以使用card元素的newcontext屬性來消除所有的變量值。
3.5?用戶輸入處理元素
通過WAP手機的按鍵,用戶可以向瀏覽器顯示的卡片中輸入數據信息或操作信息。WML為此專門提供了處理用戶輸入的元素。
3.5.1?input元素
input元素用于定義文本實體對象,包含有對輸入文本內容的格式、數據類型、長度、值、變量名等多種屬性的具體規定。當用戶輸入滿足input元素的規定時,則接收輸入信息,并賦給指定的變量靈活進行相應的操作、處理;否則,就通過瀏覽器給出具體的處理意見,并進行是單個輸入處理或變量初始化操作,比如刷新卡片以讓用戶重新輸入,或給用戶指出輸入錯誤所在并等待進一步的處理指令等。input元素是WML編程中處理用戶交互活動的重要元素,它通過單獨的<input/>標簽進行定義,其語法格式如下:
<input?name=\"variable\"?title=\"label\"?type=\"type\"?value=\"value\"?default=\"default\"?format=\"specifier\"?emptyok=\"false|true\"?size=\"n\"?maxlength=\"n\"?tabindex=\"n\"/>
其中除了name屬性是必選的以外,其他屬性都是可選的。這些屬性的功能和用法介紹如下:?1)name。該屬性用于指定用來保存用戶輸入文本的變量和名稱。定義name屬性后WML將根據該屬性也即變量名,為即將輸入的文本實體對象與之存儲空間,以便接收用戶輸入。
2)title。該屬性用于input元素的標簽,通常是位于輸入框前的提示信息。
3)type。用于指定文本輸入區的類型,有text和password兩種選擇。默認值為text,指定的用戶可以輸入文本,而且輸入的文本會同時逐漸響應并顯示在瀏覽器中。如果選擇password,則指定用戶輸入的文本作為密碼文本處理,WML程序按文本實體接收輸入的數據,而瀏覽器上響應用戶輸入顯示時逐漸均為星號(*),由此起到保密的目的。
4)value。該屬性用于指定name屬性所定義變量的值,它將顯示在輸入框中。
5)default。該屬性用于指定name屬性所定義變量的默認值。
6)format。該屬性用于格式化輸入的數據。
7)maxlength。該屬性用于指定用戶可輸入字符串的最大長度。該屬性的上限為256,最多不能超過256個字符。
8)emptyok。用于指定用戶是否可以不在輸入框內輸入內容。
9)size。該屬性用于指定輸入框的寬度,寬度值為字符個數。
10)tabindex。用于指定多個輸入框存在時,類似于HTML中Tab鍵的具體位置。
3.5.2?select元素
選擇列表屬于輸入元素,允許用戶從選項列表中選擇需要的項目。WML不僅支持單選列表,及單選項,而且支持多選列表,也就是復選項。select元素允許用戶從選列表中選擇所需的項目。列表中的選項采用后面我們就要講到的option元素進行定義,一般是一行格式化的文本。編程時,我們可以使用optgroup元素將option元素的情況項目分成不同級別或層次的選項組,為用戶選擇提供方便。
select元素是通過<select>和</select>標簽進行定義的,語法格式如下:
<select?title=\"label\"?multiple=\"false|true\"?name=\"variable\"?default=\"default\"?iname=\"index_var\"?ivalue=\"default\"?tabindex=\"n\">
內容(content)
</select>
其中所有屬性都是可選的。select元素各個屬性的功能和用法介紹如下:
1)multiple。該屬性用于指定選擇列表是否可以使用復選框。
2)name。該屬性用于指定接收選項值的變量的名稱,變量值由value屬性預設定。
3)value。用于制定name屬性所定義變量的默認值。
4)iname。用于指定包含排序號的變量的名稱。
5)ivalue。用于指定選擇列表中被選中選項的值,是一個具有排序號性質的值。?6)title。用于指定選擇列表的標題。
7)tabindex。用于指定當前選擇光標在選擇列表中的具體位置,該位置即為當前選擇操作將要選擇的選項所在的位置。
3.5.3?option元素
option元素用于定義select元素中的一組單選項。它通過<option>和</option>標簽進行定義,并可包括事件和單選項的顯示文本等信息,其語法格式如下:
<option?title=\"label\"?value=\"value\"?onpick=\"href\">
內容(content)
</option>
option元素的屬性均為可選,各屬性功能及用法說明如下:
1)value。該屬性用于設置鍵值。當用戶選到該選項之后,option元素就會將該值賦給selet元素的name屬性所指定的變量。
2)title。用于option元素制定的一個標題,以便提示用戶操作。
3)onpick。該屬性用于指定用戶選到該項并按accept鍵后所打開卡片組的L。
3.5.4?optgroup元素
optgroup元素用于將多個相關的option元素進行分組,用戶瀏覽器可以借助這種分組來安排選項列表的顯示布局,以方便用戶選擇。optgroup元素是通過<optgroup>和</optgroup>標簽進行定義的,其語法格式如下:
<optgroup?title=\"label\">
內容(content)
</optgroup>
它所包含的內容中需要包含至少一次option元素或其他的optgroup元素。
optgroup元素只有一個屬性,即title屬性,用于定義optgroup元素的標題,以便提示用戶操作。
3.5.5?fieldset元素
fieldset元素用于設定輸入框和相應的說明文本,從而用戶就可以利用input元素等借助該輸入框輸入所需的數據信息。fieldset元素的語法格式如下:
<fieldset?title=\"label\">
內容(content)
</fieldset>
由于fieldset元素和輸入有關,所以它們的內容中可以包含與輸入有關的其他元素。?其語法格式可以看出,fieldset元素只有一個屬性,即title屬性,用于定義fieldset元素的標題,以便提示用戶操作。
3.6?錨、圖像、定時器及其元素
本節我們講解與定位和定時控制有關的3類元素,包括anchor、a、img、timer幾種元素。使用它們可以在WML卡片中創建超鏈接,或在文本流中顯示一幅圖像,或設置定時器來控制用戶操作及卡片顯示等。
3.6.1?anchor元素
anchor元素用于創建一個超鏈接的頭部,超鏈接的其余部分為用戶指定的URL地址。當程序運行中用戶選中該超鏈接時,瀏覽器就會被引入到超連接指定的地址,如其他卡片組或同一卡片組中的其他卡片。
anchor元素由<anchor>和</anchor>標簽進行定義,它所包含的超連接必須是真實存在的,而且是能夠正確連接的超連接。anchor元素定位超鏈接時,必須通過相關的任務元素完成定位處理,如go元素、prev元素、refresh元素等。不過,在anchor元素中只能包含1個定位任務,多于一個時會導致WML運行錯誤。
anchor元素的語法格式如下:
<anchor?title=\"label\">
任務
文本
</anchor>
其中的任務需要包含一個進行定位的任務元素。可以看到,anchor元素只有一個屬性,即title屬性,用于定義fieldset元素的標題,它用于定義即title屬性,用于定義fieldset元素的標題,以便提示用戶操作。元素的超連接的標題。用戶瀏覽時可利用這一標題來及時了解操作的超連接的名稱或者有關提示信息。
3.6.2?a元素
a元素是由anchor元素的簡化形式,它內含了anchor元素需要包含的go元素功能愛完成超連接定位,并且不再包含其他任何變量設置。它使用<a>和</a>標簽進行定義。
3.6.3?img元素
img元素用于格式化的文本中防止和顯示一幅圖像。當然,前提是用戶所用的瀏覽器必須支持圖像顯示。img元素由單獨的<img/>標簽進行定義,它不包含其它元素。其語法格式如下:
<img?alt=\"text\"?src=\"url\"?localsrc=\"icon\"?aligh=\"alignment\"?height=\"n\"?width=\"n\"?vspace=\"n\"?hspace=\"n\"/>
屬性中alt和src是必須要有的,其他可選。另外,需要注意的是img元素要放在p元素里
,而不能放在do或option元素里。
img元素各個屬性的功能和用法介紹如下:
1)alt。該屬性用來指定當手機不支持圖像顯示用來替代現實的文字文本。
2)src。該屬性用于指定圖像文件的URL地址。
3)localscr。該屬性用來指定顯示存在手機ROM的圖標文件。
4)align。該屬性用來指定圖像顯示是相對當前文本行的對齊方式。
5)height。用于設定圖像顯示時的高度。
6)width。與height屬性類似,用于設定圖像顯示時的寬度或寬度百分比。
7)vspace。該屬性用于指定圖像顯示時的上邊距和下邊距,默認值為0。
8)hspace。與vspace屬性類似,該屬性用于指定圖像顯示時的左邊距和右邊距。
3.6.4?timer元素
timer元素用于設定一個定時器,可以延時顯示卡片組、卡片,或實現WML程序的等待操作,或在卡片組和卡片之間實現切換以取得動畫效果。
一個卡片只能使用一次timer元素,也即是說只能設置一個定時器。當用戶進入還有定時器的卡片時,定時器就會開始工作,其時間值就會逐漸減小。timer元素指定的時間值單位1/10秒。其語法格式如下:
<timer?name=\"variable\"?value=\"value\"/>
它的兩個屬性中,value屬性是必選的,name屬性為可選。name屬性用于指定表示時間值的變量的名稱,該變量的取值由定時器的時間值決定,時間值減小,該變量的值也相應地減小,并終始保持不變。
value屬性用于指定name屬性所定義變量的初始值。如果name屬性定義的變量在定時器初始化時還沒有值,那么該變量就將采用value屬性指定的值;否則,改變量就會忽視value屬性的值。如果沒有定義name屬性,也就是說,沒有指定時間變量,那么timer元素指定的定時器仍將采用value屬性的值進行延時處理。
3.7?文本格式化及其元素
WML程序中,為使顯示的文本呈現出豐富的樣式,WML提供了一些用于格式化的元素,我們通過這些元素及其相應的標簽可以對文本進行標注和控制,從而實現不同的顯示效果。
3.7.1?增強元素
增強元素都是一些成對的標簽,用于指定文本的增強顯示信息。比如b元素通過<b></b>標簽可以控制其中的文本按照粗體字進行顯示。?3.7.2?br元素
“br”即break,是用于換行的元素,它是使用單獨的<br/>標簽進行定義的。br元素的作用相當于插入一個回車符。
3.7.3?p元素
“p”即指paragraph,p元素用于劃分段落,是當前文本換行并插入一個空白行。p元素可以使用單獨的<p/>標簽進行定義,也可以使用<p>和</p>標簽成對的進行定義。其語法格式為:
<p?aligh=\"alignment\"?mode=\"wrapmode\"/>
或
<p?aligh=\"alignment\"?mode=\"wrapmode\"/>
文本
</p>
1)align。該屬性用于設置段落在瀏覽器中的對齊方式,有left、center和righ三種取值。這三種參數值分別表示p元素當前定義的文本段落及瀏覽器窗口的左側、中間和右側進行對齊。默認值為left,及段落與瀏覽器窗口的左側對齊排列。
2)mode。該屬性用于指定下一段落的換行方式。
3.7.4?td元素
td元素用于規定表格單元格的內容。其語法格式如下:
<td>?單元格內容?</td>
3.7.5?tr元素
WML中的表格是按照行、列進行組織的。一個表格由若干行組成,每行由若干列組成。tr元素用于定義表格的行。其語法格式如下:
<tr>?單元格內容?</td>
</tr>
3.7.6?table元素
table元素與tr元素、td元素一起,可用來創建能容納文本和圖像的表格,并可設置表格各列中文本和圖像的對齊方式。其語法格式如下:
<table?align=\"alignment\"?title=\"label\"?columns=\"n\">
或
<table?align=\"alignment\"?title=\"label\"?columns=\"n\">
內容
</table>
其中各個屬性的功能和用法介紹如下:
1)align。該屬性用于指定表各個列中文本和圖像的對齊方式。
2)title。該屬性用于指定table元素的標題。
3)columns.該屬性用于指定表格的列數,該數不能為0。
posted @
2006-04-29 09:42 崛起的程序員 閱讀(232) |
評論 (0) |
編輯 收藏
我們首先以Microsoft?的Internet?Infomation?Server(IIS?4或IIS?5)以及Unix平臺中最為普遍的Apache兩種Web?Server來介紹如何以它們來建制自己的WAP?Sever,將原先已經建制的Web信息平臺擴展到無限平臺之上。
1.1?WAP?Sever?Configuration
其實WAP?Sever建制非常容易,WAP在信息傳輸的部分是使用HTTP來進行的,與現有的WWW信息平臺一樣,因此,將現有的Web?Sever都可以通過對配置的調整成為WAP?Sever,提供對無線裝置的服務。
圖1.1
在WAP服務當中,所提供的新文件類型目前共有五種,以擴展名來分的話分別是wml,wmlc,wmls,wmlsc,wbmp,分別代表的是WML原始文件、WML文件的二進制碼、WML?Script的原始程序碼、WML?Script二進制碼,以及單色的Wireless?BMP文件。這些的擴展名必須新增到Web?Server的MIME?Type設定中,Web?Server才能夠提供WAP的服務。
不論使用何種Web?Sever軟件,例如Microsoft?IIS、Netscape?Enterprise?Sever、Apache、或是任何一種,只要加入以上五個MIME?Type設定,就可以提供WAP服務了。
接下來,我們就一步步帶領大家以IIS及Apache兩種不同的Server進行設定,將您的Web?Server進化成WAP?Server,以提供WAP服務。
1.2?把Microsoft?IIS?變成WAP?Server
在這一節里面,我們以IIS為例,進行MIME?Type的設定。在Windows?系統的發展過程中,到了Windows?98、Windows?NT?4.0的Option?Pack公開之后,對于WWW信息平臺的提供就變得更容易了。
本節中所使用的范例程序是IIS?5.0。但是Windows?NT?4.0?Workstation版本以及?Windows?98所使用的Personal?Web?Server(PWS)則在設定步驟上面有些差異。
首先,進入IIS的管理畫面。
啟動了IIS管理畫面之后,請選取您要管理的機器名稱,在選取了機器名稱,IIS管理畫面會將該機器上面所有的WWW站點都顯示出來。這是因為IIS中可以針對Windows?2000或Windows?NT?中所設定的不同IP位置或同一個位置中不同的Port建立多個WWW的服務。
選取了要設定的Web站點之后,請在該站點的圖示上面以鼠標右鍵點選一下,調用設定畫面,如圖1.1所示。在圖中的設定畫面選項里,可以設定包含虛擬目錄、制作清單,以及目錄安全設定等許多不同的功能,只是因為在這里我們所點選的是整個站點,因此所變更的設定將會被套用在整個站點中。
當然我們也可以只針對某幾個特定的目錄作設定,只要在特定的目錄上面按鼠標右鍵,使用該目錄的設定選項,如圖1.2所示,更改設定并套用之后就可以了。
圖1.2
設定選項之后,請直接選取“屬性”顯示變更設定內容的視窗,如圖1.3
圖1.3
在設定內容視窗中,一共包含了十大分項(這里的分項會因為IIS版本不同而有所差異)。進入設定內容視窗之后,一開始會位于整個WEB站點的主要設定部分,包含在IIS管理員中對于這個站點的名稱、讓這個Web站點對應的IP地址和Port號碼,而我們要新增的MIME?Type則要在HTTP標題的部分作設定的。
再進入了HTTP標題設定部分之后,會出現如圖1.4所示的畫面,在HTTP標題設定部分包含了四種不同的設定,分別是:啟用內容限制服務,用來設定某些特殊的目錄中的文件權限,以及自定義HTTP標題,用來設定自定義HTTP?header?meta資料,第三個是內容分級。可以將一個目錄或站點中的文件內容設定為內含某種等級的文件,例如暴力、性、不當文字與言語等,第四個部分就是我們現在要設定的部分:MIME對應,將某個特定的擴展名與MIME?type。
圖1.4
接下來,請點擊文件類型這個按鍵,調用MIME?type設定畫面,如圖1.5所示。
圖1.5
在圖1.5中的新類型按鍵上面以鼠標左鍵點選之后,就會出現圖1.6的輸入畫面,此時我們要將前述的五個MIME?type一次一次的輸入到擴展名與內容類型之中。當然了,一次只能輸入一種新的擴展名與MIME?Type的對應。而輸入完成之后在IIS?5.0與4.0中就可以直接使用這些新的文件類型了。
圖1.6
而Windows?NT?workstation或是Windows?98中的Personal?Web?Server(PWS)的設定方法有很大的差別。
因為在PWS之中并沒有特別讓使用者輸入資料的設定界面,所有的PWS的MIME?Type都是使用Windows操作系統內部的MIME?Type對應資料的,因此我們必須在Windows資源管理器中的文件類型這部分來做新增的動作。
首先我們需要點擊資源管理器上面的工具選項,選擇其中的文件夾選項這個項目,調用設定系統配置的視窗界面,如圖1.6所示。
一開始畫面將會顯示在第一頁的設定部分,也就是圖1.6中的“查看”那一頁,我們新增的MIME?Type的部分是位于文件類型的設定頁中,因此我們必須以鼠標左鍵點擊文件類型的Tag以切換到該設定頁。此時以鼠標左鍵點擊圖1.6中的新建類型按鈕,則會出現圖1.7所示畫面。
新增類型包含了:文件描述、關聯擴展名、內容、類型,也就是MIME?type,褂姓飧隼嘈偷腦ど璧睦┱姑T叢赪indows?NT系統中還需要將對新增的文件類型加入所謂開啟、編輯等對應動作的處理程序與參數設定,但是現在新增的MIME?type只是為了在Personal?Web?Server(PWS)上面提供新的MIME?type,因此便不用在此指定其他相對應的動作所要啟動的程序。但讀者如果想在Windows資源管理器當中以鼠標雙擊該文件進入編輯器來處理這個文件的話,請暗下動作選項(A)下面的新增按鈕,則可以選擇以系統中的那個程序來處理該種文件。
不過要注意到的是,目前的環境中還沒有比較好的WML編輯器,所能用的應該也就是幾個電信大廠所提供的工具了,所以讀者也可以使用目前在網絡上極為流行的幾種文字編輯器來處理WML文件,像筆者就是以UltraEdit?6.0作為對WML文件的處理程序。
在Windows?NT?Workstation或Windows?98當中設定好了這些新的MIME?type之后,必須重新啟動計算機,讓系統更新對于文件類型的對應,然后Personal?Web?Server(PWS)才能夠提供WAP服務。
1.3?將Apache?升級為WAP?Server
Apache可以說是目前所有跨平臺的Web?Server軟件中支持最多平臺的一個,它的前身是NCSA的httpd,一開始這個軟件在改版的時候就已經考慮到大多數的操作系統平臺了,包含了NT,Linux、以及各種不同的Unix操作系統,在這里我們將以Linux配合Apache作為設定的例子。
1.3.1?Apache?系統介紹
Apache系統比較像NCSA的httpd(因為是同一群工程師將原來的程序改良而成的),只是后來的Apache比前期的NCSA?httpd增加了許多功能,像Apache提供了同步執行多個處理程序的功能,使得NCSA?httpd原本效能不良的問題獲得了長足的改善。現在,只要你使用的是Unix或者Linux系列的操作系統,同時也使用Apache作為你的Web?Server的話,你可以再列出全部處理程序的時候看到其中有許多個httpd處理程序同時在執行。
Apache使用了同時維持一定的未忙閑狀態的處理程序來改善效能問題。因為舊有的NCSA?httpd言用所有的UNIX上面的成學習法方法,將所有的功能大都以一個處理程序(process)作為提供者。而在1995-2000這幾年中,Web的使用者的數量極為快速的增加,因而就系統以單一處理程序提供服務的方式越來越不受歡迎,而在CGI與互動程序的效能與支持上面也增加了許多的功能。
例如在互動程序上新增了PHP程序的支持、JAVA?Servlet、JSP,甚至于還支持Windows?IIS系統中的ASP程序的功能,都是讓許多人不斷支持Apache的原因。除此之外,Apache對于CGI效能的提升也作了極大的改良,除了提供程序人員開發可植入Apache系統的界面,用以提升常用程序的效能之外,還針對一般CGI的效能問題與安全問題作了改善。
在把Apache?Server裝到Linux系統上面之后,Linux系統的/etc目錄下就會新增一個httpd目錄,用來存放所有的Apache的配置設定文件,而執行文件httpd則會被存放在/usb/sbin目錄中,同時還會將一個名為mime.types的文件放到/etc目錄下面。
且不論Apache里頭的其他設定(這部分的設定文件都在/etc/httpd/conf底下,包含了目錄的權限、虛擬目錄的對應、以及Sever本身的其他相關的設定)MIME?type的設定值需要修改/etc/mime.types這個文件即可。
/etc/MIME.types這個文件中儲存的是以行作分隔的MIME?types設定,每一行為一個獨立的MIME?type,如果要對應到特定的擴展區的話,就直接在MIME?type之后留一個空白字符,在打上擴展名。以wmlc為例,必須在文件中加入以下這一行設定:
application/vnd.wap.wmlc?wmlc
完成之后,重新啟動Apache,Apache就可以提供wmlc這個文件類型讓使用者端存取了,當然,在第一節中所介紹的五個MIME?type也都得加到設定文件中才能提供完整的WAP服務。
1.4?建立WAP的測試環境
在WAP編程與開發中,為了對所編寫的網頁及應用進行測試,我們通常要建立WAP的測試環境。一般來說,WAP測試環境可以從瀏覽器環境、模擬環境、實際環境三個方面進行建立,本節就對此進行基本的介紹。
1.4.1?瀏覽器環境
瀏覽環境的建立十分簡單。目前Internet尚有許多站點提供有WML瀏覽器的免費下載服務。比較著名的WML瀏覽器是Winwap(http://www.wapschool.com/chinese/download/winwap22.exe)以及各移動通信設備公司提供的瀏覽器。安裝這些瀏覽器后,用戶就可以在Windows系統環境下訪問WAP站點,查看WAP頁面。
在WAP的服務器端,開發人員則可以利用Windows?NT?4.0或Windows?2000以及Internet信息服務器IIS(Internet?Information?Server?4.0/5.0)軟件進行模擬。在原有的WWW服務子目錄下再建立一個WAP子目錄,將所有的WML網頁放在其中,并對IIS進行必要的配置。然后,在WWW服務器正常運轉的情況下,開發人員通過在Winwap等WAP瀏覽器中輸入http://locallhost(本地計算機名)/wap/index.xml的形式,即可進入WAP網頁進行瀏覽測試。
這種測試環境的優點是實施起來比較簡單,建設比較快,操作起來也比較簡單易學。其不足之處在于,這種測試用的瀏覽器畢竟是Windows環境下的瀏覽器,支持大部分的WML標記,查看窗口的界面可以擴大和縮小,比較自由,因而所看到的測試效果與實際手機上的效果可能會有比較大的差別,而且它也不能提供編輯、編譯和調試的集成環境。
1.4.2?模擬環境
用于WAP測試的模擬環境是通過使用移動通信設備公司所提供的WAP手機模擬器來實現WML瀏覽的。目前可以從各公司站點上下載的模擬器有Nokia?Toolkit、Ericsson?R1.0?Emulator、Ericsson?WapIDE、UpPhone?UP>Simulator、Motorola?Mobile?ADK等。
相比較來說,Nokia和Motorola提供了比較完整地結成開發環境,其它兩家主要提供了模擬WAP手機的WML瀏覽。由于模擬器一般都是供直接的HTML服務器直接連接,所以WAP服務器端只需要Windows?NT/2000及IIS?4.0/5.0?軟件即可進行模擬和調試。與上面介紹的方法一樣,在WWW服務器工作正常的情況下,通過輸入http://locallhost(本地計算機名)/wap/index.xml的形式,即可對WAP網頁進行瀏覽測試。
雖然說這種模擬環境提供了集成環境及與WAP手機基本一致的模擬器,但仍難保證所用模擬器與其實際產品完全一致,尤其是沒有WAP網關的參與,因此這是一種并不完備的檢測。特別的,這種模擬環境下與無線電話應用WTA(Wireless?Telephony?Application)相關的服務根本沒有辦法進行檢測。不過,對于單純的開發測試來說,這樣模擬環境基本能滿足要求。
1.4.3.?實際環境
WAP測試的實際環境中需要WAP手機、網卡及服務器三個部分,因此,為了建立WAP測試的實際環境,開發者需要購買一些主流的WAP手機,同時使用前面介紹的方法在原來的HTML服務器上建立一個WAP專用的虛擬目錄,已建立WAP服務器,然后使用現有網關或夾在移動通信公司提供的相應網關,那么只要三者都能順利正確的工作,開發者就可以通過WAP手機對WAP網頁及應用進行測試了。
1.5?完成WAP設定之后
在完成WAP設定之后,我們就可以開始提供給所有的使用者WAP服務了,當然,在這之前,還必須將Content(內容)準備好,也就是說,我們還得先將WML文件與相關的應用程序準備一下。
posted @
2006-04-29 09:38 崛起的程序員 閱讀(286) |
評論 (0) |
編輯 收藏
完成WAP服務器的建立和WAP瀏覽器的安裝之后,我們接下來就可以使用WML語言來編寫WAP網頁或應用,并通過WAP服務器及瀏覽器進行調試。從本章開始我們將系統地學習WML語言,本章主要講解WML語言的基礎知識,下一章全面講解WML的語法、標簽和規則。?
2.1?WML的簡單例子及編輯、測試方法
無限標記語言WML(Wireless?Markup?Language)是一種基于擴展標記語言XML(Extension?Markup?Language)的語言,是XML的子集。它可以顯示各種文字、圖像等數據,是由WAP論壇(http://www.wapforum.org)提出并專為無線設備用戶提供交互界面而設計的,目前版本為1.1版。這些無線設備包括移動電話,呼機和個人數字助理PDA(Personal?Digital?Assistants)等。
2.1.1?WML與WAP設備
為了更好的了解和使用WML語言,開發人員應對WML使用的設備和支持WML的設備的特點、特征有個大概的了解。
一般而言,WML使用的無線設備通常具有以下特點:
與普通的個人計算機相比,體積較小;
設備的內存有限,且其CPU性能也有限;
通訊帶寬較窄、時延較長。
以移動電話、PDA為例來講,支持WML的設備主要具有以下特征:
有一個顯示屏幕,可顯示2.兇址啃?2各字符;2.兇址型ǔ0ūA舾δ馨磁サ囊恍校?br>支持數字和字符的輸入;
支持操作者使用箭頭或數字按鈕進行選擇;
支持ASCII的可打印碼;
通常都有兩個可編程功能鍵,即Accpet鍵和Options鍵,一般安排在接近鍵盤的屏幕下方;
通常有一個Prev導航鍵。
我們介紹WML所使用WAP設備的目的,是希望讀者通過WAP設備的特點、特征來了解WML語言的特點,進而對WML編程所要解決的問題有個大概的認識。
2.1.2?使用文本編輯器面寫WML程序
使用WML語言編寫WAP網頁或應用時,需要使用一個編輯器進行編輯。與HTML編程一樣,WML編寫的程序也是純文件文本,可以使用任意文本編輯器進行編寫,比如Windows系統中的“記事本(NotePad)”等。也可以使用比如Nokia?WAP?Toolkie等軟件(有關此具體的用法會在以后的學習過程中提起)。我們先介紹第一種方法,隨后介紹第二種。
如果要使用\"記事本(NotePad)\"來編寫WML程序,則可以在Windows系統中,單擊“開始”按鈕,然后從出現的菜單中,依次將光標指向“程序”、“附件”、“記事本”,啟動“記事本”程序。屏幕上隨后就會出現它的編輯窗口,從中就可以輸入并編寫WML程序了。
作為舉例,我們可以輸入如下簡單的程序。
<?xml?version=\"1.0\"?>
<!DOCTYPE?wml?PUBLIC?\"-//wapforun//DTD?WML?1.1//EN\"?\"http://www.wapforum.org/DTD/wml_1.1.xml\">
<xml>
<card?id=\"card1\"?title=\"Title\">
<P>
<!--Write?your?card?implementation?here.-->
Hello?World!!
</P>
</card>
</xml>?
輸完后將它保存為hello.xml文件。保存時注意文件的擴展名應為xml而不是txt。
2.2?WML程序結構
上一節我們降解了一個簡單的WML程序,具有HTML編程的讀者可以看出,WML程序在結構上形式上與html程序有很多相似之處。下面我們就根據一個實例來分析一下WML程序的結構及組成。
2.2.1?WML的元素和標簽
分析實例之前,我們有必要對WML的元素和標簽予以簡單說明。與HTML類似,WML的主要語法也是元素和標簽。元素是符合DTD(文檔類似定義)的文檔組成部分,如title(文檔標題)、IMG(圖像)、table(表格)等等,元素名不區分大小寫。WML使用標簽來規定元素的屬性和它在文檔中的位置。標簽使用小于號(<)和大于號(>)括起來,即采用“<標簽名>”的形式。標簽分單獨出現的標簽和成對出現的標簽兩種。大多數標簽是成對出現的,由首標簽和尾標簽組成。首標簽和尾標簽又分別稱為起始標簽和終止標簽。首標簽的格式為“<元素名>”,尾標簽的格式為“</元素名>”。成對標簽用于規定元素所含的范圍,比?lt;b>和</b>標簽用于界定黑體字的范圍,也就是說<b>和</b>之間包住的部分采用黑體字顯示。單獨標簽的格式為“<元素名/>”,他的作用是在相應的位置插入元素。如〈br/〉標簽表示在該標簽所在位置插入一個換行符。
2.2.2?WML程序結構形式及組成的實例分析
了解了上述知識后,下面我們在分析一個實例程序。程序如下:
<?xml?version=\"1.0\"?>
<!DOCTYPE?wml?PUBLIC?\"-//WAPFORUM//DTD?WML?1.1//EN\"?\"http://www.wapfourm.org/DTD/wml_1.1.xml\">
<wml>
<card?id=\"card1\"?ontimer=\"#card2\"?title=\"Tookit?Demo\">
<timer?value=\"50\"/>
<p?aligh=\"center\">
</br></br></br>
<big>
<!--Write?your?card?implementation?here.-->
Welcome?to....
</big>
</p>
</card>
<card?id-\"card2\"?ontimer=\"#card?3\"title=\"Toolkit?Demo\">
<timer?value=\"50\"/>
<p?align=\"center\">
<br/><br/>
<b>
The?Nokia<br/>
</b>
Wireless?Application?Protocol
</u>
...
</p>
</card>
<card?id=\"card3\"title=\"Toolkit?Demo\">
<p?align=\"center\">
<br/><br/><br/>
<big>
<i>
Toolkit
</i>
</big>
</p>
</card>
</xml>?
該程序運行后將在WAP手機屏幕依次顯示3屏信息。先顯示\"Welcome?to?...\",然后顯示\"The?Nokia?Wireless?Application?Protocol...\",最后顯示\"Tookit!\"。顯示時每屏都有標題\"Tookit?Demo\",相鄰兩屏之間延時為50,其單位大小為1/10秒,延時50即5秒。
通過以上實例我們可以了解到WML程序的結構形式及組成:
1)語法。WML與HTML極為相似。仍然是一種標記語言,并且延續了XML的語法規則,具體的語法我們會以后的學習過程中遇到。
2)文件聲明。所有的WML程序必須在文件的開頭處聲明XML文件類型,包括XML的版本,WML的文檔類型、所用規范等。聲明形式如下:
<?xml?version=\"1.0\">
<!DOCTYPE?wml?PUBLIC?\"-//WAPFORUM//DTD?WML?1.1//EN\"?\"http://www.wapforum.org/DTD/wml_1.1.xml\">?
3)標簽。在WML語言中需要使用標簽(Tag),其使用形式與HTML和XML等標記語言中的形式是完全一致的。
4)元素。WML的元素(Element)用于描述卡片組(Deck)的標記信息即結構信息。一個元素通常有一個首標簽、內容、其它元素及一個尾標簽組成,具有下述兩種結構之一:
<首標簽>內容</尾標簽>
或
<標簽/>
元素包含的內容中還可以有元素,這些元素也是有首標簽、相應內容、其它元素及尾標簽組成。不包含內容的元素成為空元素。它為一個單獨的標簽。或者說,單獨的標簽也是一種元素。
5)屬性。WML與XML一樣,其標簽可以包含很多屬性。屬性用于給標簽提供必要的附加信息,且屬性內容通常在起始標簽內使用。不過,屬性內容不會被瀏覽器顯示,它至作為參數為標簽提供必要的信息。
指明屬性值的時候,需要把該值用引號擴起來,可以是單引號或者雙引號,引號通常成對嵌套使用。屬性名稱必須小寫。例如:<card?id=\"card?1\"?ontimer=\"#card2\"?title=\"Toolkit?Demo\">
而且,單引號的屬性中還可以包含雙引號的屬性。實體字符也可以作為屬性值。實體字符是指諸如&、<、>、'、\"的特殊字符,在WML程序中顯示著類字符需要特殊處理,后面我們介紹具體方法。
6)注釋。WML程序中也可以加入注釋。注釋內容用于給開發人員順利閱讀源代碼提供方便,它不會被瀏覽器顯示出來。注釋內容在標簽中用感嘆號(!)引出,并用于<!--注釋內容-->的形式。例如:<!--?Write?your?card?implementation?here.-->。需要說明的是,XML程序中不支持注釋的嵌套。
7)文檔結構。WML文檔是由“卡片(Card)”和“卡片組(Deck)”構成的,一個Deck是一個或多個Card的集合。當客戶端發出請求之后,WML即從網絡上把Deck發送到客戶瀏覽器,這是用戶就可以瀏覽Deck內包含的所有Card,而不必從網上單獨下載每一個Card,程序中的第一個Card是缺省得可見的Card。
注意:Deck是一副紙牌的意思,這里是指一疊卡片,所以我們在這里稱之為它為“卡片組”。另外,Card指的是WAP手機屏幕大小的網頁,盡管有時一個Card可能需要多屏才能顯示完,但我們也可以把它翻譯成“頁面”,不過這樣與HTML中的頁面容易混合。因此我們在這里稱之為卡片。
2.2.3?WML程序的基本結構
以上我們簡單分析了WML的程序結構及組成,由此大家可以對WML程序有個整體上的初步認識。下面我們給出WML程序的基本結構。
<?xml?version=\"1.0\"?>
<!DOCTYPE?wml?PUBLIC?\"-//WAPFORUM//DTD?WML?1.1//EN\"?\"http://www.wapforum.org/DTD/wml_1.1xml\">
<wml>
<head>
<access/>
<meta..../>
</head>
<card>
Some?contents...
</card>
<wml>?
該基本結構可以分為以下幾個關鍵部分:
1)聲明。WML程序有許多Deck組成,對于每一個Deck,在其文檔開頭必須進行XML的聲明和文檔類型DOCTYPE的聲明。
XML聲明總是在文件的第一行,注意前面最好不要有空格或者還行:
<?xml?version=\"1.0\"?>
2)緊跟著是DOCTYPE聲明,注意聲明是字母的大小寫不要搞錯:
<!DOCTYPE?wml?PUBLIC?\"-//WAPFORUM//DTD?WML?1.1//EN\"?\"http://www.wapforum.org/DTD/wml_1.1xml\">
3)<xml>標簽。該標簽用于包含和定義WML的一個Deck。它有一個可選的xml:lang屬性來制定文檔的語言,比如<wml?xml:lang=\"zh\">表示文檔語言為中文。
4)<head>標簽。該標簽用于包含和定義Deck的相關信息。<head>標簽之間可以包含一個<access>標簽和多個<meta>標簽。
5)<access/>標簽。它的一般形式是<access?domain=\"域\"?path=\"/路徑\"/>,主要用于制定當前Deck的訪問控制信息,有兩個可選的屬性。其中,domain用來制定域,默認值為當前域,path用來制定路徑,默認值為“/”,即跟目錄。由于<access>單獨使用,所以要用“/”結尾,后面我們還會系統的講解WML的各種標簽,這里即使看不懂也沒關系,主要有些感性的認識就可以了。
6)<meta...>標簽。它的一般形式是<meta?屬性?content=\"值\"?scheme\"格式\"?forua=\"true|false\"/>,用于提供當前Deck的meta信息,包括內存數據處理方式,以及數據傳輸方式和處理方式等。有關該標簽的詳細內容我們后面會專門給出。
7)<card>標簽。一個Deck可以包含多個Card,每個Card的內容可能不止一屏顯示。對于每一個Card,WML均使用<card>和</card>進行包含和定義。?<card>同時可以包含多個可選的屬性,如<card?id=\"name\"?title=\"label\"?newcontext=\"false\"?ordered=\"true\"?onenterforwand=\"url\"?pmemterbackward=\"url\"?ontimer=\"url\">。至于這些屬性的具體含義及功能,我們將在后面介紹。
2.3?WML語言的基本知識
上一節我們介紹了WML程序的基本結構,接下來我們介紹WML語言的基本知識,主要包括WML的字符集、變量、數據類型及WML程序的基本組成部分等。
2.3.1?WML的字符集及編碼
WML使用XML的字符集,即通用字符集ISO/IEC-1062.,也即統一字符編碼標準Unicode?2.0。同時,WML還支持其他系列的字符集子集,例如UTF-8、ISO-8859-1或UCS-2等。其中:
UTF-8是指通用字符集UCS(Universal?Character?Set)的轉換格式8(Transformation?Format?8),主要傳輸國際字符集的轉換編碼。UTF-8采用了UCS字符的8位編碼,提供了十分安全的編碼格式,可以有效避免數據傳輸過程中的竊聽、截取及非法解密。同時,UTF-8與7位ACSII碼完全兼容,不會影響此類編碼實現的程序;它的編碼規則十分嚴格,能夠有效避免同步傳輸錯誤,而且還會支持其它字符集提供了足夠的空間。
ISO-8859-1字符集是國際標準化組織ISO(International?Standardization?Organization)制定的ACSII字符集的擴展集,能夠表示所有西歐語言的字符。與ISO?Latin-1一樣,ISO-8859-1與Windows環境中普遍使用的美國國家標準協會ANSI(American?National?Standards?Institute)的字符集極為類似,絕大多數情況下無需區分。在不特別指明的情況下,HTTP協議均使用ISOLatin-1字符集。因此,為了WML頁面中表示非ACSII(non-ACSII)字符,開發人員需要使用相應的ISO?Latin-1編碼的字符。
UCS-2是ISO?1062.標準中自定義的通用多8位編碼字符集(Universal?Multiple-Octer?Coded?Character?Set)的2字節(即16位)編碼標準,其字符編碼值與Unicode字符的標準編碼值相等。
WML文檔可以采用HTML?2.0規范所定義的任何字符編碼標準經編碼處理。一般說來,WML文檔的字符編碼是需要轉換為另外的編碼格式,以與WAP用戶的手機瀏覽器所用字符標準相適應,否則,手機瀏覽器就無法顯示WML頁面中的字符。然而,編碼轉換時可能會丟失一些字符信息,所以,如果在用戶端進行WML文檔的編碼轉換,那么就可能導致某些結果信息丟失而不能被用戶所瀏覽。因此,如有必要,我們應當盡量在WML頁面傳送到用戶瀏覽器之前完成編碼轉換。
為了解決這一問題,一方面,我們需要為Web服務器補充定義WML的數據類型,以讓服務器可以準確傳輸這些數據,另一方面,我們需要制訂編碼轉換的原則。
2.3.2?WML字符使用基本規則
WML是一種比較嚴格的語言,字符使用必須遵守相應的規則,這些基本規則主要包括以下幾個方面:
1)大小寫敏感。在WML中,無論是標簽元素還是屬性內容都是大小寫敏感的,這一點繼承了XML的嚴格特性,任何大小寫錯誤都可能導致訪問錯誤。
一般來說,WML的所有標簽,屬性,規定和枚舉及它們的可接受值必須小寫,Card的名字和變量可大寫和小寫,但它是區分大小寫的。包括參數的名字和參數的數值都是大小寫敏感的,例如variable1、Variable1和vaRiable1都是不同的參數。?2)空格。對于連續的空字符,程序運行時只需要一個空格。屬性名、符號(=)和值之間不能有空格。
3)標簽。標簽內屬性的值必須使用雙引號(\")或單引號(')括起來。對于不成對出現的標簽,必須在大于號(>)前加上順斜杠(/),比如換行標簽必須寫成<br/>才正確。
4)不顯示的內容。在WML中,不顯示的字符主要包括換行符、回車符、空格和水平制表符,它們的8位十六進制內碼分別為10、13、32及9。
程序執行時,WML將忽視所有的多于一個以上的不顯示字符,即WML會把一個或多個連續的換行、回車、水平制表符及空格轉換成一個空個。
5)保留字符。這是WML的一些特殊字符,如小于號(<)、大于號(>)、單引號“'”、雙引號“\"”、和號(&)。
6)顯示漢字。如果希望WML程序執行時能夠顯示漢字,則只需要程序開頭使用encoding指定漢字字符集即可。例如:<?xml?version=\"1.0\"?encoding=\"gb2312\">。
注意:指定漢字字符集的形式和方法可能因為開發工具或WAP手機的不同而不同。
2.3.3?變量
WML編程中可以使用變量,變量使用前必須進行定義。變量一旦在Deck中的某一個Card上定義過,其他Card則可以不必重新定義就能直接調用該變量。
定義變量的語法格式為:
$identifier
$(identifier)
$(identifier:conversion)
其中identifier指變量名,或說變量標示符;conversion指變量的替代。
變量名是由US-ACSII碼、下劃線和數字組成的,并且只能以US-ACSII碼開頭。變量名嚴格區分大小寫,也即,變量名是大小寫敏感的。
定義變量的語法在WML中享有最高的解釋優先級。
有關變量的使用說明如下:
1)在WML中,變量可以在字符串中使用,并且在運行中可以更新變量的值。
2)當變量等同于空字符串時,變量將處于未設置狀態,也就是空(Null)。
3)當變量不等同于空字符串時,變量將處于設置狀態,也就是非空(Not?Null)狀態。
4)在“$identifier”形式下,WML通常以變量名后面的一個空格表示該變量名的結束。如果在某些情況下空格無法表示一個變量名的結束,或者變量名中包含有空格,則必須使用括號將變量名括起來,即采用“$(identifier)”的形式。
WML程序中的變量是可以替代的,我們可以把變量的數值賦給Card中的某一文本。有關變量替代說明如下:
1)在WML程序中,只有文本部分才可以實現替代。
2)替代一般在運行期發生,而且替代不會影響變量現在的值。
3)任何標簽是按照字符串替代的方式實現的。
4)替代是按照字符串替代的方式實現的。
由于變量在語法中有最好的優先級,包含變量聲明字符的字符串將被當作變量對待,所以如果要使程序顯示“$”符號,則需要連續使用兩個“$”進行說明。例如:<p>?Your?acconut?has?$$15.00?in?it?</p>一句顯示的結果為:Your?account?has?$15.00?in?it。
2.3.2.?WML核心數據類型
WML的核心數據類型均屬于字符型數據,是根據XML的數據類型定義的,共有下述2.擲嘈停?1)CDATA型。這種數據類型是WML用得最多的一種,可以是數字、字符串或包含數字的字符串。不過定義時,不論是數字或字符串,都必須以文本的形式定義,及數據用引號引起來。CDATA型的數據僅用于屬性值。例如\"$(value)\"或name=\"value\"等。注意,這里的value指CDATA型的數據值。
2)PCDATA型。這是從CDATA中分解出來的一類數據,除了可以是文本形式的數字、字符串或兩者的混合串外,還可以是WML的標簽。PCDATA型的數據只能用于WML的元素表示。
3)NMTOKEN型。這是一類特殊的數據,凡是包含或部分包含數字、字母及標點符號的數據均屬于NMTOKEN型數據。這種數據可以用標點符號開頭,但不用于定義變量名或元素名。
4)id型。專門用于定義WML元素名稱的數據類型。
在這2.擲嘈橢校珻DATA型用起來比較靈活,它可以使變量或數據免于語法檢查。這是因為,CDATA內的數據內容都會被當作文本來處理,從而可以避免WML的語法檢查,直接作為文本顯示出來。
2.3.5?WML數據值性質
除了NMTOKEN型數據外,WML其他3種數據都必須以文本形式即加上引號進行定義。我們關心的問題是,這些類型的數據可以表示哪些數據值呢?或者說,它們所表示的數據值的性質是什么呢?
事實上,WML數據只在性質上可以是長度(Length)、宏變量(Vdata)、流(Flow)、內行(Inline)、布局(Layout)、文本(Text)、超鏈(Href)、布爾值(Boolean)、數據(Number)或增強方式(Emphasis)。
2.3.6?卡片與卡片組
前面我們分析了WML程序的結構時,曾將講到WML文檔的信息是通過卡片集和卡片組集的形式進行組織的。一個Deck是一個或多個Card的集合。當客戶終端發出請求之后,WML即從網絡上把Deck發送到客戶的瀏覽器,Deck是服務器發送信息的最小單位。用戶瀏覽器收到Deck后,可以瀏覽其中包含的所有Card。Card用于表示或描述一個或多個用戶交互單位。
2.3.7?卡片組模板
同一卡片組通常會含有許多卡片,這些卡片的定義、屬性或格式通常都大同小異。如果我們逐一定義各個卡片,顯然是十分麻煩的。為此,WML提供了卡片組模板的功能,模板內定義了一系列標準和參數,可以應用到同一卡片組的所有卡片中去,從而能夠大大地提高我們的編程效率。有關卡片組模板的內容我們后面會專門介紹的。
2.3.8?WML與URL、程序段錨點
我們知道,環球網WWW是各種信息和設備的網絡,為保證全球范圍內的交互,人們制定了3種規范:其一,統一資源定位器URL提供所有網絡資源的標準命名方式和定位方式;其二,標準協議,如HTTP協議等,提供WWW資源的傳輸方式;其三。標準內容類型,如HTML、WML,提供WWW資源的內容形式及標準。WML沿用了這些規范,并擴大了URL使用的范圍。在WML中,不僅超連接、文件路徑及文件名可以作為URL處理,卡片名、宏變量名及各種內部資源名等也可作為URL處理。
為此,WML改進了HTML命名資源位置的方式,采用程序錨點(Fragment?Anchor)的形式來處理WML程序中某段程序的地位。程序段錨點根據文檔WML規則進行定義,并按照程序段表示符前加井字好(#)的方式書寫。使用程序段錨點,WML程序可以在同一卡片組中定位不同的卡片。如果在程序中不指定程序段,那么程序中引用的URL名稱則指整個卡片組,而且卡片組的名稱同時也是本卡片組內的第一個卡片的名稱。?2.3.9?瀏覽器操作歷史
為了在瀏覽器端管理WML程序的執行,WML使用“瀏覽器前后關系”的功能保存WML程序執行的狀態及各種參數、變量等,這樣可以用來記錄用戶的操作情況。同時,WML還提供了一個簡單的導航歷史模型,以URL地址的形式記錄了用戶瀏覽時的各種操作,并把這些URL地址放入歷史推棧。通過推棧,用戶即可實現歷史瀏覽的回潮及其它操作。
posted @
2006-04-29 09:31 崛起的程序員 閱讀(169) |
評論 (0) |
編輯 收藏
目前的手機游戲基本分為兩類:一是文字類,二是圖形類。
文字類游戲
文字類的游戲主要分為WAP在線游戲和短信互動游戲。
WAP游戲主要以手機上網的方式去進行游戲,也就是WAP網絡支持,WAP是手機上網的一種通訊協定,其意義相當于TCP/IP。由于手機的畫面有限,所呈現的網頁也必須做精簡化處理,所需要的網頁編寫語言就是WML,相當于HTML,而相對于目前互聯網上的WWW,手機也會有自己的MMM網站,所以才成為WAP游戲。有些象我們目前所玩的網頁游戲,一般來講角色扮演類游戲比較多,需要手機上網的支持,所以水貨手機就別想了……登陸移動夢網或者聯通無限找到其對應的游戲頻道即可進行了,一般收費是包月制,每月4到8左右。隨著技術的進步,現在已經出現了圖形化的WAP社區類游戲,玩家甚至可以上傳自己的照片讓其它玩家看到。
?短信游戲是以發送短信的形式進行游戲的。?發送游戲SP固定特服號開始參與游戲。首先注冊游戲(一般為包月制)如:同城約會:移動用戶發送123到456,聯通用戶發送123到789(?移動和聯通使用不同的特服號)發送后會馬上收到系統反饋信息,反饋信息中會有多重選擇并應帶有資費情況,(一般是確認是否訂制)根據反饋信息選擇,并回復相應指令到固定特服號。確定完成后將收到下一條系統回復信息,一般需要用戶注冊自己在游戲中的資料了。游戲不同,規則也不同,填好信息發送,注冊成功開始游戲。用戶向系統發送每一條短信后,自然會收到一條回復信息,并根據信息提示決定下一步的方向。如想結束游戲,可根據游戲開始前系統發送的規則說明中的指令退出操作。
圖形類游戲
這里著重推薦的是圖形類游戲。圖形類分為下載類和內置類。
下載類以Kjava和Brew以及聯通新推出的Unijava為主。大概這幾個名字可以說是耳熟能詳了,不過他們僅僅是編寫程序的語言,而對于我們只需要知道這個是圖形類的游戲就夠了。圖形類的游戲目前已經達到了早起電視游戲或者電腦游戲的水平,根據玩家按鍵的不同,圖像中的人物做著不同的動作,從而完成一系列的任務,目前大多以動作游戲占主流,兼備益智游戲、角色扮演、體育游戲、競技游戲、射擊游戲等多種多樣的游戲,可以說是百花爭放,陸續有大量的好游戲等著你呢。圖形類的游戲可玩性高,種類豐富。所以被所有廠商視為發展的重點。
內置類為手機本身自帶的游戲,早期的游戲在手機中無法更換和刪除,如NOKIA的貪吃蛇。現在也是可以更換和刪除的。目前的內置式游戲越來越有趣,如摩托v303中的波斯王子,K700的3D網球。所以在選購手機的時候,這也是一個很大的參考價值哦。
玩手機游戲具體需要哪些設備?
想玩短信游戲?
目前市面上的所有手機幾乎都是支持中文短信的,只要您的手機支持,那么玩起短信游戲是沒問題的了。
想玩WAP游戲?
和短信游戲需要短信支持一樣,想網WAP游戲就要看你的手機支持不支持WAP了。早期的GSM手機可能無法直接登陸WAP的,因為早期的手機當中沒有將登陸WAP的帳號和密碼集成在手機當中。而后期的手機將帳號和密碼集成在手機之中了,那么就可以輕松的登陸了,如果您的手機登陸WAP時需要提供帳號和密碼的話,只能去移動通信大廳或者聯通通信大廳去看看他們是否還提供這項業務了。若是連接不正確,先確認自己的手機業務是否開通了移動夢網或者聯通無限,確認無誤后可以參照下面的設置進行設置。
新手上路:如何設置才能登陸移動夢網?
新手上路:如何設置才能登陸聯通無限?
登陸后,進入游戲的項目就可以選擇你喜歡的游戲進行游戲了。
想玩下載的圖形游戲?
基本根據下載方式的不同可能需要的設備也不同了。
1.登陸WAP去下載。這里就就需要手機支持WAP了,具體設置以及操作和上面的WAP游戲一樣,不過是進入不同的選項,移動夢網進入“百寶箱-游戲百寶箱”去下載,聯通無限進入“聯通神奇寶典-軟件超市-軟件目錄-游戲天地”中去下載。
2.短信的方式下載。同樣需要手機支持WAP網絡并且能登陸的,只是減少了你選擇游戲所花費的時間和昂貴的流量費用。直接從短信得到下載地址的連接。
3.電腦下載傳輸到手機上。根據傳輸的方式不同,也需要不同的設備。可以分為機種傳輸的模式:藍牙、紅外線、數據線。依次也就需要藍牙設備、紅外設備和手機傳輸數據線了。由于操作較為麻煩并且需要一定的設備和電腦知識,這里暫不做討論。?
如何開通中國移動GPRS服務?
1.?如何申請使用GPRS服務?
答:現在中國移動GPRS服務正在試商用,GPRS手機用戶可以申請使用。正式商用時,如果您買了GPRS手機,還需要申請開通GPRS業務功能。申請開通GPRS業務功能就和開通其他新業務一樣,到營業廳填寫業務變更表或直接打電話1860申請開通即可。
2.?GPRS如何收費?
答:目前GPRS按流量進行計費,用戶可以選擇以下四種套餐:
月租費(元)?贈送的免費流量數(MB)?超過免費流量后的費用(元/KB)?
自由套餐?0?0?0.03?
經濟套餐?20?1?0.01
時尚套餐?100?20?0.01?
商務套餐?200?不限量使用?
另外,用戶漫游不加收漫游費。?
申請GPRS?功能不需要開戶費,您只要撥打電話1860或到營業廳申請開通GPRS服務即可。此處資費供參考,如與各地移動公司有出入,各地以本地移動公司的資費為準。
3.?按量收費和按時間收費有什么區別?
答:按時間收費就是按照從接入網絡至與網絡斷開的時間長度進行計費;按流量收費就是按照接入網絡后產生的實際數據比特流來進行計費,接入了網絡但沒有數據傳遞是不收費的。
例如用戶在瀏覽網頁的時候,新打開一個窗口然后進行閱讀,產生了5kByte的流量,則只收用戶5kB的錢,閱讀的時間是不收費的;用戶進行網上聊天,在一個小時內發送或者接收了6條信息,流量為1kB,則只收1kB的錢,而不是按一小時來收費;用戶下載一首mp3,流量為4M,然后在線收聽,則收費為?4M的流量費用,收聽的時候是不收費的。
GPRS為用戶上網提供了一種更好、更快、更優質的服務,而且是完全按照實際流量來收費,收費更合理,因此也能為您省錢。
4.?GPRS需要換手機、換號、換卡嗎?要不要開戶費?
答:使用GPRS業務就要換一個GPRS手機,不需要換號,不需要換卡,只需要打開GPRS業務功能,無需開戶費。
5.?使用GPRS手機如何設置?有何簡化程序嗎?
答:使用GPRS?手機需要設一個連接(APN)設置(使用WAP業務設為CMWAP,使用其他www業務使用CMNET),用戶名和密碼設置為空,其他設置與原來的WAP設置一樣。目前ericsson的手機在部分省市能夠支持通過短信空中下載GPRS和WAP的設置。
6.?GPRS的覆蓋和漫游情況如何?可不可以漫游?
答:目前中國移動GPRS網絡覆蓋全國16省25個城市,今年10月份馬上就可以覆蓋全國所有省會城市和大部分大中城市。在國內GPRS覆蓋的地方都可以實現GPRS?的自動漫游,且用戶漫游不加收漫游費。
在沒有GPRS網絡的時間GPRS?手機還可以用,可以進行正常通話和CSD方式的數據業務,但GPRS的業務就不能使用了。
7.?GPRS與原來的CSD(電路交換)撥號方式如何切換?
答:在進行數據業務之前(如使用WAP)選擇使用的連接方式,或者CSD?的撥號方式或者GPRS方式,要切換的話需要先關閉原來的業務再重新進行連接方式的選擇。比如:用戶啟動WAP瀏覽器,手機會跳出菜單讓你選擇連接方式,(或默認為缺省的連接設置)如選擇了GPRS,那么用戶就會通過GPRS?瀏覽WAP的各類信息、游戲等,用戶要換成撥號接入WAP,則需要推出WAP瀏覽器,選擇連接方式為撥號,再啟動WAP瀏覽器才能切換至撥號(CSD)方式的WAP。?
8.?用戶購買了支持GPRS的手機之后,可享受哪些新的增值業務?
答:目前用戶可以使用所有原有的WAP上面的信息與娛樂服務以外,還可以通過GPRS手機+筆記本或Pocket?PC等設備進行www瀏覽,另外用戶還可以通過GPRS手機直接收發POP3?email、進行網上聊天、網上會議、移動炒股、移動商務、移動娛樂、網上購物等等。
9.?使用GPRS上網時,能否接電話和接收短信?
答:可以。使用GPRS上網不影響正常的通話和接收短信。
如何開通CDMA手機網絡服務?
1、如何開通CDMA手機網絡服務?
在您購買CDMA手機的時候,請詢問經銷商,您的手機是否支持上網服務,是否默認開通上網服務,一般提供上網服務的CDMA手機是默認開通的。上網服務是按照您訪問網絡所成生的數據流量來計算的。如果您的CDMA手機需要進行一些設置才可以進行手機上網,那么請參照您的手機說明書,或詢問經銷商以及相關網站。
2、CDMA手機網絡服務資費標準(以下資費如超過流量,均按照0.005元/KB計算流量)
套餐種類(普通CDMA用戶)??資費標準?
互動世界(用于手機上網)?0.01元/KB?
互動世界低速上網
(用于手機上網)?0.1元/分鐘?
掌中寬帶
(用于外接電腦上網)?98元獲得1000MB流量,198元獲得5000MB流量,298元獲得8000MB流量??
套餐種類(133月租號碼)?資費標準?
聯通無限隨身定制(5元)?5元獲得1700KB的流量(漫游則獲得流量無效,按照0.005元/KB計算)?
聯通無限隨身定制(15元)?15元獲得8.5MB流量(漫游則獲得流量無效,按照0.005元/KB計算)?
聯通無限隨身定制(35元)?不限制流量(漫游則獲得流量無效,按照0.005元/KB計算)??
posted @
2006-04-29 09:21 崛起的程序員 閱讀(242) |
評論 (0) |
編輯 收藏