大家应该对这两个词很熟悉了,但是对词里包含的意义可能并不是特别清楚。首先必须说明的是,程序员和系统分析员不存在谁高级谁低级的分别,他们是两种职业,对职业技能的要求完全不同。所以厉害的程序员就是系统分析员的说法是不对的。当然,系统分析员的技能要求他必须要懂得如何写程序,但是他的重心在于如何把一个很大的项目切割成适合个人的小块,然后将这些小块组织起来。程序员的职责就是如何更好更快的实现这些小块。
在这章之前,我们讨论的都是一个合格的程序员应当具备的技能,当然不止那一些内容。之所以在这里插进来讨论系统分析员的事情,是因为我们的栏目叫做软件工程而不是程序员从入门到精通之类的。
在正式开始之前,我们还是来看在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 崛起的程序员 阅读(223) |
评论 (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 崛起的程序员 阅读(169) |
评论 (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 崛起的程序员 阅读(958) |
评论 (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 崛起的程序员 阅读(180) |
评论 (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 崛起的程序员 阅读(378) |
评论 (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 崛起的程序员 阅读(184) |
评论 (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 崛起的程序员 阅读(229) |
评论 (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 崛起的程序员 阅读(283) |
评论 (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 崛起的程序员 阅读(164) |
评论 (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 崛起的程序员 阅读(236) |
评论 (0) |
编辑 收藏