当前位置:主页 > 网页教程 > 网页制作 > wap网站教程 > 内容欢迎大家投稿

WAP建站入门教程六、动态输出WML页面

时间:2009-10-03 08:19来源:未知 作者:大宝库 点击:读取中
阅读工具:字体:

 

使用多种服务器端脚本语言动态输出WML页面

 
   以下将要讲述的是使用各种服务器端脚本语言编写动态输出WML页面。这里主要以几种最常见服务器端编程方式为例子。其他的服务器端编程方式都可以依此类推。
    无论使用哪种服务器端编程方式来动态输出WML页面,其关键就是输出Content-type为text/vnd.wap.wml。然后按照WML的语法格式输出WML内容就可以达到目的。当然其中针对不同的编程方式还有一些细节问题。

 
使用ASP动态输出WML页面

    • 使用记事本输入下面的ASP程序(图2-26):
<%@ Language=VBScript %>
<% Response.ContentType="text/vnd.wap.wml" %><?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml">
<wml>
    <card id="main" title="ASP WML">
        <p>
            Hello
        </p>
    </card>
</wml>

图 2-26 Hello.asp
    • 保存为hello.asp。并且是它和hello.wml在同一个子目录下。注意:记事本在保存的时候只识别txt文件扩展名,因此在保存之后应该手工修改文件扩展名。为了方便起见,可以使用其他的文本编辑工具,或者是使用专门的ASP编辑工具(例如:Viusal InterDev)。
    • 启动IIS服务器管理。在“默认的Web站点”下找到“wap”目录,用鼠标右键点击它,选择属性“Properties”,就会弹出一个对话框,里面有好多配置选项。 在“虚拟目录”标签页当中有一项应用程序设置。将“许可”一项设置为:“执行(包括脚本)”。确定后,退出IIS Console。
    • 打开WinWAP,马上Stop它,在URL栏里输入:“http://127.0.0.1/wap/hello.asp”,并按下回车。等着欣赏第一个ASP页面(图2-27)。

图 2-25 WinWAP测试结果显示
    • 如果读者熟悉ASP,读者也许会注意到:为什么在<?xml version="1.0"?>并没有换行写。注意,这是必须的!否则,程序在WinWAP下可能没有任何问题,但是在其他模拟器上,可能就会导致编译错误!因为在<?xml version="1.0"?>前面不允许有多余的空格或者换行。
CGI编程时应该注意的问题
    使用CGI程序生成动态WML页面和使用CGI编程生成动态HTML的方式基本一样。只是在返回WML页面前,先要输出Content-Type为text/vnd.wap.wml,然后再输出WML内容。
    输出的返回格式:"Content-type: text/vnd.wap.wml\n\n"。
使用标准C动态输出WML页面
    这里有一个非常简单的标准C例子,该例子适合于Windows和Unix。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
void GenerateCGIHeader();
void GenerateCGIFooter();
/*--------------------------------------------------------------*/
int main(int argc, char* argv[])
{
    char tmpBuf[128];
    char strGET[]="GET";

    if (getenv("REQUEST_METHOD") == NULL)
    {
        printf("This script is not intended to run from shell.\n");
        return -1;
    }

    // Check that the request method is GET (see CGI specs)
    strcpy(tmpBuf, getenv("REQUEST_METHOD"));
    if (strcmp(tmpBuf, strGET) != 0)
    {
        printf("This script requires use of GET-method.\n");
        return -1;
    }

    /* Create a header for our reply */
    GenerateCGIHeader();

    /* Display operating system-style date and time. */
    _strtime( tmpBuf );
    printf( "OS time:%s\n", tmpBuf );
    _strdate( tmpBuf );
    printf( "OS date:%s\n", tmpBuf );

    /* Create a footer for our reply */
    GenerateCGIFooter();
    return 0;
}

/*--------------------------------------------------------------*/
void GenerateCGIHeader()
{
    /* Generate header for CGI response */
    printf("Status: 200\n");
    printf("Content-type: text/vnd.wap.wml\n\n");
    printf("<?xml version=\"1.0\"?>\n");
    printf("<!DOCTYPE wml PUBLIC \"-//WAPFORUM//DTD WML 1.1//EN");
    printf("\" \"http://www.wapforum.org/DTD/wml_1.1.xml\">\n");
    printf("<wml>\n");
    printf(" <template>\n");
    printf(" <do type=\"prev\" label=\"Back\">\n");
    printf(" <prev/>\n");
    printf(" </do>\n");
    printf(" </template>\n");
    printf(" <card id=\"datecard\" title=\"CGIDate\">\n");
    printf(" <p>\n");
}

/*--------------------------------------------------------------*/
void GenerateCGIFooter()
{
    /* Generate footer for CGI response */
    printf(" </p>\n");
    printf(" </card>\n");
    printf("</wml>\n");
}
    在Windows环境下,使用Viusal C&C++ 6.0创建一个Windows Console Application——WapCCGI。然后将该文件加入到项目中,编译生成WapCCGI.exe。将该可执行文件拷贝到wap子目录下。启动Nokia WAP Toolkit,在“Go”下选择“Open Location”,并输入URL地址(图2-28):

图 2-26 输入URL地址
    在选择“OK”以后,模拟器上出现系统当前的日期和时间(图2-29):
    对于Perl编程,其基本原理符合CGI编程原理。先看下面的程序片段:
# HTTP header with correct MIME type
print "Content-type: text/vnd.wap.wml\n\n";

# WML starts here with the correct XML doc type declaration
print "<?xml version=\"1.0\"?>";
print "<!DOCTYPE wml PUBLIC \"-//WAPFORUM//DTD WML 1.1//EN\"";
print "\"http://www.wapforum.org/DTD/wml_1.1.xml\">";
……
更多的Perl 代码,输出WML页面内容。
……
    按照以上的程序开头便可以输出动态的WML页面。下面有一段更详细的教程,这个教程是为以下开发者准备的:
    • 知道如何编写WML页面和卡片,并且了解自己的工作。
    • 知道如何配置自己服务器,使之能够运行Perl。
    • 有CGI的基本知识,并且了解Perl的语法。
    从表面上来说,使用CGI来产生WML页面和产生HTML页面没有太大的区别。一旦读者仔细地看一下,就会明白WML所包含的新内容的确还是与其他的页面动态生成有所不同。
    假设,老板需要做一个可以通过电话来访问电话目录。公司现在只有两个职员,但是将要不断扩大。因此,肯定不会去做一个固化的目录。相反将把数据保存在一个文本文件中,通过动态生成WML页面的来显示信息。
    首先,将要建立一个“people_data.txt”,如下所示:
# Format is:
# Name|phone num|fax num|Title
Linus Smith|123-4567|098-7654|Director of OS Development
Jane Doe|123-4568|098-7655|Senior VP of OS Research
    可以看出“|”符号是用来区别字段的。“#”是用来表示注释的。这些字符没有其他的意义,仅仅是一般的转换。
    下面,需要决定最后的WML文件将是什么样子。在同老板商量之后,决定如下:
<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml">
<wml>
<card title="Telephone Book" id="index">
    <p>
        Welcome to Widgets Inc. Telephone Book
        <a href="#view">Click to view list</a>
    </p>
</card>
<card title="List of Names" id="view">
    <p>
        <a href="#linus_info">Linus Smith - 123-4567</a>
        <a href="#jane_info">Jane Doe - 123-4568</a>
    </p>
</card>
<card title="Info for Linus Smith" id="linus_info">
    <p>
        Director of OS development
        Phone number: 123-4567
        Fax number: 098-7654
    </p>
</card>
<card title="Info for Jane Doe" id="jane_info">
    <p>
        Senior VP of OS research
        Phone number: 123-4568
        Fax number: 098-7655
    </p>
</card>
</wml>
    每当增加新成员的时候,都不得不重新修改文件。这不是一个好办法。但是如果向文本文件中增加内容,那将是一个不会编写WML页面的程序员也会的事情。为了实现这个目标,使用以下的脚本:
#!/usr/bin/perl –w
use strict;
use CGI qw/:standard/;

# Our CGI object
my $q = new CGI;
    以上的内容是设置Perl环境。使用CGI模块来进行HTTP数据显示和处理。然而在这个例子当中,将使用尽量少的CGI模块,读者将会在将来的教程当中明白处理服务是多么的复杂。
# data file to get info from
my $data = "people_data.txt";

# Template for the title card
my $title_card = qq (
<card title="Telephone Book" id="index">
<p>
Welcome to Widgets Inc. Telephone Book<br/>
<a href="#view">Click to view list</a>
</p>
</card>
);

# Initial id of the first record
my $id = "a";
    这里已经创建了一个字符串,它将作为标题卡片。当然还有需要创建的动态ID。(选择‘a’,是因为它是一个简单的字符,可以很容易地增加)既然每个记录都有唯一的ID(因此可以把它作为头一个卡片)。ID将从‘a’开始,然后每找到一个新记录就增加一个。要一次性将所有的名字都生成卡片。然后使用一个初始化的缓冲区来显示成员的数据内容。
# Now iterate over the
data file building data dynamically
open(FILE,"$data") || die "Can't open $data: $!\n";
while (<FILE>) {
chomp;
next if (/^\#/);
my ($name, $phone, $fax, $position) = split(/\|/);
    打开自己的文件(当然要检查打开权限,保证能够打开),现在就可以读取了(注意:要跳过以“#”开头的行)。其他的部分,只需要从已经定义和产生的文件中读取就可以了。显然在读取的过程当中,需要做一定的检查,保证每个部分的确有数据。
# Build up the view card
$view_card .= build_view_card($name, $phone, $fax, $position);
# Build up info cards
$all_info_card .= build_info_card($name, $phone, $fax, $position);
}
    这里,将从文件中提取的数据传给两个函数。他们将返回由这些参数所确定的卡片。注意到Perl的“.= ”操作符,函数返回的字符串将不断地扩充。
# Finish off the card

$view_card .= "</p> </card>";

my $header = qq (
<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN"
"http://www.wapforum.org/DTD/wml.xml">
);

# Template for the entire deck
my $deck = qq(
$header
<wml>
$title_card
$view_card
$all_info_card
</wml>
);
print $q->header('text/vnd.wap.wml');
print $deck;
    这里非常简单地将他们绑在一起。打印文件头,建立卡片,并且将他们动态地放在一起。当做好这一切之后,需要输出一个Content-type头        text/vnd.wap.wml。
    现在来看一下建立卡片的两个子过程:
sub build_view_card {
$id++;
my ($name, $phone, $fax, $position) = @_;
my $info_item = qq (
<a href="#$id">$name - $phone</a><br/>
);
return $info_item;
}
    这个代码将接收信息,并把这些信息插入到一个简单的模板里面。一个非常重要的一点是每次都在增加“$id”变量的数值。这个保证每个记录都有唯一的id号。Perl允许直接使用“++”操作符,使得从‘a’增加到‘b’。
sub build_info_card {
# Template for card showing info for a single person
my ($name, $phone, $fax, $position) = @_;
my $info_card = qq (
<card title="Info for $name" id="$id">
<p>
$position<br/>
Phone number: $phone <br/>
Fax number: $fax <br/>
<do type="prev"><prev/></do>
</p>
</card>
);
return $info_card;
}
    在这个子过程当中,做了和前面一样的事情,只不过用了不同的模板。注意到已经在前面的函数中增加了“$id”的数值,因此,在这个函数中只需要返回一个新的卡片就可以了。
    这就是全部过程,现在已经有了一个动态的电话本。当然这个教程不是一个很好的解决办法,至少他需要一个人手工来修改txt文件。另外,WML页面有大小的限制。但是无论如何,以上就是全部的过程。
 
使用PHP动态输出WML页面
请先看一个简单的PHP例子:
<?php
header ("Content-Type: text/vnd.wap.wml");
echo "<?xml version=\"1.0\"?>\n"
?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" http://www.wapforum.org/DTD/wml_1.1.xml">
<!-- Source Generated by WML Deck Decoder -->
<wml>
<card id=”main” title=”PHP WML”>
    <p>
        <?php
            echo "hello,world\n";
        ?>
    </p>
</card>
</wml>
    启动Nokia WAP Toolkit,在“Go”下选择“Open Location”,并输入URL地址(图2-30):

图 2-30 输入URL地址
    使用Nokia WAP Toolkit测试结果显示如下(图2-31):

图 2-31 测试结果显示
    下面演示的是如何使用WML与PHP实现动态交互。演示的内容是:用户在WML页面中输入用户名和密码,然后提交给服务器端;服务器端将动态生成WML显示用户的输入,并返还到客户端。整个演示包括登录页面logon.wml和服务端脚本程序logon.php。
logon.wml

<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml">
<!-- Source Generated by WML Deck Decoder -->
<wml>
<card>
    <p>
        User:<input name="user" value="admin"/>
        Password:<input name="password" value="whoami"/>
    </p>
    <do type="accept">
        <go href="http://127.0.0.1/php4/logon.php">
            <postfield name="user" value="$(user)"/>
            <postfield name="password" value="$(password)"/>
        </go>
    </do>
</card>
</wml>

logon.php

<?php
    header ("Content-Type: text/vnd.wap.wml");
    echo "<?xml version=\"1.0\"?>\n"
?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml">
<!-- Source Generated by WML Deck Decoder -->
<wml>
<card>
    <p>
        <?php
            echo "Hello ! $(user) <br/>\n";
            echo "Password is $(password) <br/>\n";
        ?>
    </p>
</card>
</wml>
    启动Nokia WAP Toolkit,在“Go”下选择“Open Location”,并输入URL地址(图2-32):

图 2-32 输入URL地址
    在模拟器上出现(图2-33):

图 2-33 登录界面
    在确定输入后(图2-34):

图 2-34 从服务器端返回的处理结果
使用Servlet动态输出WML页面
    下面有两个简单的例子程序,先看第一个简单例子:
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class WapServlet extends HttpServlet
{
    protected void service(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, java.io.IOException
    {
        response.setContentType("text/vnd.wap.wml");
        PrintWriter out = response.getWriter();

        xmlHeader(out);
        out.println("<wml>");
        out.println("<card title = \"JavaTest\">");
        out.println("<p>Hello! This comes from a servlet!</p>");
        out.println("</card>");
        out.println("</wml>");
    }

    public void xmlHeader(PrintWriter out)
    {
        out.println("<?xml version=\"1.0\"?>");
        out.println("<!DOCTYPE wml PUBLIC \"-//WAPFORUM//DTD WML 1.1//EN\" "+"\"http://www.wapforum.org/DTD/wml_1.1.xml\">");
    }
}
    下面是Nokia提供的一个例子程序:
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
/*
* HelloWorldServlet - a very simple servlet
*/

public class HelloWorld extends HttpServlet
{
    String m_text;

    // the initialization parameter is read during
    // the initialization of the servlet
    public void init(ServletConfig config) throws ServletException
    {
        super.init(config);
        m_text = config.getInitParameter("text");
        if (m_text == null)
        {
            m_text = "This is a simple test servlet.";
        }
    }

    public void doGet(HttpServletRequest request,HttpServletResponse response) throws IOException, ServletException
    {
        PrintWriter out = response.getWriter();
        out.println("<?xml version=\"1.0\"?>");
        out.println("<!DOCTYPE wml PUBLIC \"-//WAPFORUM//DTD WML1.1//EN\"\"http://www.wapforum.org/DTD/wml_1.1.xml\">");
        out.println("<wml>");
        out.println("<card id=\"card1\" title=\"Hello World\">");
        out.println("<p>");

        out.println(m_text);
        out.println("</p>");
        out.println("</card>");
        out.println("</wml>");

        // Remember to close the out object
        out.close();
    }

    public String getServletInfo()
    {
        return "The simple HelloWorld servlet.";
    }
}
使用JSP动态输出WML页面
  先看一个简单的例子程序:
<?xml version="1.0"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml">
<% response.setContentType("text/vnd.wap.wml"); %>
<wml>
<card id="start">
    <do type="accept">
        <go href="index.jsp#test"/>
    </do>
    <p>
        JSP Test:<br/>
        Press accept to continue!<br/>
    </p>
</card>

<card id="test">
    <do type="prev">
        <prev/>
    </do>
<%
    out.println("<p>");
    out.println("Hello from script code!<br/>");
    out.println("</p>");
%>
</card>
</wml>
    下面将要演示使用WML和Java Server API如何简单快速地在WAP终端上生成动态的WML页面。这里将不再去讲每个WML标记的作用,而是给出一个简单的例子。这个例子体现出整个语言的特点。
    这个JSP例子显示了为一个移动用户定时更新约会的例子,例如:做一个给家里打电话的应用程序。这个应用是在Windows NT下使用Java Server Web Development Kit(JSWDK)1.01和JSWDK配套的服务端工具,来建立的JSP页面。使用Nokia WAP Toolkit 1.2测试和浏览应用。
    一个典型的路径还包括在移动电话和WAP内容服务之间的一个WAP网关。这样安排的主要原因是要对WML进行编码,这样来适应其窄带的特点。但是Nokia WAP Toolkit包含了这样一个编译器,因此它可以直接从HTTP服务器提取WML内容(在例子里是从服务端工具上来取的)。
    当建立WAP应用的时候,必须记住一点。WAP设备的显示屏幕很小——典型的只有4行12个字符,不要使用过多的滚动。这样会使用户十分烦心。数据的输入功能也十分有限。而且设备的RAM有限,CPU的能力有限。并且现在无线网络的带宽有限而且高延时。因此WAP的应用程序应当短小,简单。
    应用程序包括两个页面。第一个是“pick_appointment.jsp”。它有一个选择卡片。当用户选择了其中的一个约会时间的时候,就会进入到“show_appointment_data.jsp”页面(中间还传递了约会的ID号)。第二个页面有两个卡片。第一个显示会面的时间,第二个显示数据输入,允许工程师通过输入ID取消约会。
    动态的约会数据是通过JavaBean的实例来取得的。在这里没有它的代码,总的来说是通过JDBC连接到数据库的过程。取消的过程是通过Servlet来操作的,在这里其程序也没有显示。既然用户可能随时取消某个约会,因此需要定时地刷新“pick_appointment.jsp”。
pick_appointment.jsp

<%@ page language="java" contentType="text/vnd.wap.wml" %>
<jsp:useBean id="appointmentBean" class="mwebber.samples.AppointmentBean" scope="application" />
<%!
   // This convenience method builds our <option> elements, one for each appointment.
    private String getOptions(mwebber.samples.AppointmentBean appointmentBean)
    {
        StringBuffer sb = new StringBuffer();
        int[] appointmentIDs = appointmentBean.getAppointmentIDs();
        for(int i=0; i<appointmentIDs.length; i++)
        {
            sb.append("<option onpick=\"show_appointment_data.jsp?id=");
            sb.append(i);
            sb.append("\">");
            sb.append(appointmentBean.getAppointmentTime(i));
            sb.append("</option>");
        }
        return sb.toString();
    }
%>
<%! String strXMLPrologue = "<?xml version=\"1.0\"?>"; %>
<%-- WML CONTENT BEGINS --%>
<%= strXMLPrologue %>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml">

<wml>
<card id="pick" title="Appointments">
    <!-- Refresh the deck every minute -->
    <onevent type="ontimer">
        <go href="pick_appointment.jsp"/>
    </onevent>
    <timer value="600"/>

    <!-- Display a widget to navigate back by one in the history stack -->
    <do type="prev">
        <prev/>
    </do>
    <!-- Display the "select" widget of appointments to pick -->
    <p>
        <select title="Appointments">
        <%= getOptions(appointmentBean) %>
        </select>
    </p>
</card>
</wml>
<%-- WML CONTENT ENDS --%>
show_appointment_data.jsp

<%@ page language="java" contentType="text/vnd.wap.wml" %>
<jsp:useBean id="appointmentBean" class="mwebber.samples.AppointmentBean" scope="application" />
<%
    // Grab the "id" parameter, using the in-built reference to the request object.
    int intAppointmentID = Integer.parseInt(request.getParameter("id"));
%>
<%! String strXMLPrologue = "<?xml version=\"1.0\"?>"; %>
<%-- WML CONTENT BEGINS --%>
<%= strXMLPrologue %>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml">

<wml>
<card id="main_data" title="Main Data">
    <p align="center">
        <b>
            <%= appointmentBean.getAppointmentTime(intAppointmentID) %>
        </b>
    </p>
    <p>
        <br/>
            <%= appointmentBean.getAppointmentDetails(intAppointmentID) %>
        <br/>
        <a href="#check_off">Check off this appointment</a><br/>
        <a href="http://localhost:8080/pick_appointment.jsp">Back to appointments list</a>
    </p>
</card>

<card id="check_off" title="Check Off">
    <!-- Set up a widget to send the input field data to the server -->
    <do type="accept">
        <go href="/servlet/ProcessCheckOff" method="post">
            <postfield name="check_off_code" value="$check_off_code"/>
        </go>
    </do>
    <p>
        <input name="check_off_code" emptyok="false" maxlength="6"/>
    </p>
    <p>
        <a href="#main_data">Back to appointment data</a>
        <br/>
        <a href="http://localhost:8080/pick_appointment.jsp">Back to appointments list</a>
    </p>
</card>
</wml>
<%-- WML CONTENT ENDS --%>
    在每一文件的开头,都要设置正确的MIME文件类型。如果文件类型不对,那么这个页面将遭到模拟器的拒绝。在这个例子里,“text/vnd.wap.wml”表明是WML页面。其他类型例如“text/vnd.wap.wmlscript”是WMLScript源代码,而“image/vnd.wap.wbmp” 是WBMP文件。
    既然WML页面是一个XML文档,因此它包含了标准的XML文件头和一个DTD头,但是“<?”和“?>”标记显然与JSP的标记有混合。因此将这一段隐藏到字符串变量当中。别忘记JSP将被编译成Java源文件,最后成为Servlet。
(责任编辑:大宝库)


------分隔线----------------------------
推荐内容
  • WAP手机上网问题问与答

    一、我如何键入网址? 1、打开手机,进入服务功能选项 2、按下确定键 3、选中书签 4、...

  • WML语法大全

    WML是一种基于XML(扩展标记语言)的一种标记语言。这种语言是为无线设备用户提供交互...

  • 全面解析WAP技术

    什么是WAP WAP就是无线应用协议(WirelessApplicationProtocol)的简称。虽然它跟联合国...

  • 用QuickWAP组件建设Wap站点

    用QuickWAP组件建设Wap站点教程-准备篇 首先我们要简单了解一下什么是QuickWAP,Quick...

赞助商链接
赞助商链接