本章介绍 Net.Data 宏的不同组成部分,以及它们如何在一个应用程序中一起工作的。
本节以一个简单的 Net.Data 宏来说明宏语言的成份。 在这个宏例子中创建了一个表,它提示您输入要传送给 REXX 程序的信息。 这个宏将此信息 传送给外部的 REXX 程序 OMPSAMP.CMD,此程序回送用户输入的数据。 然后,其结果显示在第二个 HTML 页中。
先看一下整个宏,然后细致到每个模块:
%{ ********************** 定义模块 ************************%}
%DEFINE {
page_title="Net.Data macro Template"
%}
%{ ********************** 函数定义模块 ************************%}
%FUNCTION(DTW_REXX) rexx1 (IN input) returns(result)
{ %EXEC{ompsamp.cmd %}
%}
%FUNCTION(DTW_REXX) today () RETURNS(result)
{
result = date()
%}
%{ ********************** HTML 模块:输入 ************************%}
%HTML(INPUT) {
<html>
<head>
<title>$(page_title)<title>
</head><body>
<h1>Input Form</h1>
Today is @today()
<FORM METHOD="post" ACTION="output">
Type some data to pass to a REXX program:
<INPUT NAME="input_data" TYPE="text" SIZE="30">
<p>
<INPUT TYPE="submit" VALUE="Enter">
<hr>
<p>[<a href="/">Home page]
</body></html>
%}
%{ ********************** HTML 模块:输出 ************************%}
%HTML (OUTPUT) {
<html>
<head>
<title>$(page_title)</title>
</head><body>
<h1>Output Page</h1>
<p>@rexx1(input_data)
<p><hr>
<p>[<a href="/">Home page</a> |
<a href="input">Previous page</a>]
</body></html>
%}
这个宏包含四个较大的模块:DEFINE、FUNCTION 和两个 HTML 模块。在一个 NET.Data 宏中 可以有多个 DEFINE、FUNCTION 和 HTML 模块。
这两个 HTML 模块包含熟悉的 HTML 标记,这方便了 Web 宏的编写。 如果您熟悉 HTML,那么构建一个宏只是简单地添加一些在服务器上动态处理的宏语句和发送 给数据库的 SQL 。
虽然这个宏看起来类似于一个 HTML 文档,但是 Web 服务器作为 CGI 程序或 Web 服 务器 API 通过 Net.Data 访问它。 Net.Data 要求两个参数:要处理的宏的名称,和这个宏在其中显示的 HTML 模块。
当调用此宏文件时,Net.Data 从开头处理它。 下一节看一下 Net.Data 处理此文件时发生的事。
%{ ********************** 定义模块 ************************%}
%DEFINE {
page_title="Net.Data macro Template"
%}
第一行是一个注解行。注解是 %{ 和 %} 之间 的任何文本。注解必须在其它的宏模块的外面。 下一语句是一个 DEFINE 模块的开始。在一个定义模块中,可以定义多个变量。 在此例中,只定义了一个变量 page_title。变量一旦定义,就可以在这个宏的任何地方用 $(page_title) 语法来引用。变量的使用可以使以后对宏的全局更改更容易些。 这个模块的 %} 标志此 DEFINE 模块结束。
下一模块是函数定义模块,但是先看一下例子中的称为 INPUT 的那个 HTML 模块。
%{ ********************** HTML 模块:输入 ************************%}
%HTML (INPUT) { <--- 标识此 HTML 模块的名称。
<html>
<head>
<title>$(page_title)</title> <--- 注意此变量替换。
</head><body>
<h1>Input Form</h1>
Today is @today() <--- 此行包含一个函数调用。
<FORM METHOD="post" ACTION="output"> <--- 当此表提交时,
"output" HTML 模块被调用。
输入要传递到 REXX 程序的一些数据:
<INPUT NAME="input_data" <--- "input_data" 在此表提交时定义,
TYPE="text" SIZE="30"> 并且可以在这个宏的其它地方引用,
它被初始化为用户在输入区中键入的内容。
<p>
<INPUT TYPE="submit" VALUE="Enter">
<hr>
<p>
[
<a href="/">Home page</a>]
</body><html>
%} <--- 关闭此 HTML 模块。
这个模块包含一个带一输入区的简单表的 HTML 。整个模块由 HTML 模块标识符 %HTML (INPUT) { ... %}括起来。INPUT 标识这个模块的名称。 可以给它任何名称。HTML <title> 标记中包含一个宏置换的例子。 变量 page_title 的内容置换成此表的标题。
这个模块也有一个函数调用的例子。表达式 @today() 是对函数 today 的调用。此函数在后面描述的 FUNCTION 模块中定义。 today 函数的结果,当前的日期,被插入到 @today() 表达式所在位置的 HTML 文本。
FORM 语句中的 ACTION 参数是在 HTML 模块之间,或在宏之间游历的例子。当这个表被 提交时,ACTION 参数中对另一模块名称的引用将访问那个模块。 来自一个 HTML 表的任何输 入数据作为隐式变量而被传送。对于定义在这个表中的单个字段,当表被提交时,在这个 字段中输入的数据被传递到 HTML output 模块的 input_data 变 量中。
您可以在其它的宏文件中用相关引用来访问 HTML 模块,只要这些宏文件在同样的 Web 服务器上。例如,ACTION="../othermacro.mac/main" 访问宏文件 othermacro.mac 中称 为 main 的 HTML 模块。另外,输入到表中的任何数据被传递到这个宏的变量 input_data 中。
当调用 Net.Data 时,此变量作为 URL 的一部分被传送。例如:
<a href="/cgi-bin/db2www/othermacro.mac/main?input_data=value">Next macro</a>
不需要象在大部分 CGI 程序中那样处理环境变量以接收输入数据。 Net.Data 会 为您处理它们。您只需要引用这些变量名。
下一个 HTML 模块是 OUTPUT 模块。
%{ ********************** HTML 模块:输出 ************************%}
%HTML (OUTPUT) {
<html>
<head>
<title>$(page_title)</title> <--- 又一个替换
</head><body>
<h1>Output Page</h1>
<p>@rexx1(input_data) <--- 此行包含一个对函数 rexx1 的调用,
它传送变量 “input_data”。
<p>
<hr>
<p>
[
<a href="/">Home page</a> |
<a href="input">Previous page</a>]
%}
与 INPUT 模块类似,本模块是标准的 HTML,其中用宏语句替换变量和一个函数调用。 page_title 变量被替换到 title 语句中。并且如前所述,本模块中包含一个函数调用。 这里调用了函数 rexx1 ,并将从 INPUT 表中接收来的变量 input_data 的内容传 递给这个函数。 可以把任意个数的变量传递给一个函数,或从一个函数中传出来。 要传递 的变量个数及其类型是由函数定义确定的。
有关函数的更多信息,请参阅 "函数定义模块"。
%{ ********************** 函数定义模块 ************************%}
%FUNCTION(DTW_REXX) rexx1 (IN input) returns(result) { <-- 此函数接受
一个参数,并且返回一个
结果,该结果替换
关联的函数
调用
%EXEC{ompsamp.cmd %} <-- 此函数执行一个外部的 REXX 程序,
其名为 "ompsamp.cmd"
%}
%FUNCTION(DTW_REXX) today () RETURNS(result) {
result = date() <-- 这个函数的单个源语句
包含直接插入。
%}
这个函数定义模块中包含两个函数说明。 第一个, rexx1, 是一个 REXX 函数说明,它执行一个称为 ompsamp.cmd的外部 REXX 程序。这个函数接受一个输入变量 input,并将它自动地 传递给外部 REXX 命令。 REXX 命令也返回一个称为 result 的变量。REXX 命令中 result 变量的内容替换了 OUTPUT 模块中 包含的 @rexx1() 函数调用。 变量 input 和 result 被 REXX 程 序直接可存取,象在源程序 ompsamp.cmd 中显示的:
/* REXX */ result = 'The REXX program received "'input'" from the macro.'
这个函数中的代码将回显传递给它的数据。 可以将结果文本格式化为您需要的形式, 这只需将请求的 @rexx1() 函数调用包含在正常的 HTML 形式标记(如<b> 或 <em>) 中即可。 不使用 result 变量,REXX 程序通过 REXX SAY 语句就可以将 HTML 标记写入标准输出。
第二个函数说明,today,也引用了一个 REXX 程序。 但在这里,整个 REXX 程序(只有一行)包含在函数说明中。 不需要有外部程序。 REXX 和 PERL 函数都允许直接插入程序,因为它们是解释型语言,可以动态进行语法分析和动态执 行。 直接插入程序具有简明性,不需要管理一个分离的程序文件。 第一个 REXX 函数也 可以使用直接插入方法来处理。
Net.Data 允许您定义和引用一个 Net.Data 宏中的变量。 另外,还可以将这些变量从宏传递给环境变量,或从环境变量传递回宏。 Net.Data 令牌 ,例如变量名和引用字符串,可以包含多达 64KB 数据。对于 OS/400,最大尺寸取决于该 系统。
宏变量分成如下类型:
一个标识符(它是一个变量或函数调用)被说明或实例化时,成为可见的 ( 即,可引用的)。 标识符在其中是可见的那个区域,称为它的作用域。有五类作用域:
在一个宏文件中,可以在任何地方引用的标识符,具有全局作用域。 具有全局作用域的标识符是:
其说明出现在任何模块外面的标识符具有这个作用域。 模块以 “{” 开始,以 “%}”结束。(注意,DEFINE 模块不属于这个定义,应当作为单个 DEFINE 语句对待。)一个具有宏文件作用域的标识符从其被说明的地方到宏文件结束都是可见的。
在 FUNCTION 内说明或实例化的标识符具有函数模块作用域。 (这也适用于在函数的 REPORT 或 ROW 模块中引用的变量,但不是由 Net.Data 在宏文件中明确或非明确定义的)。
只可以在 REPORT 模块中引用的标识符具有报表模块作用域(例如,表格列名 N1 ,N2,..., Nn)。只有那些由 Net.Data 明确定义为它的 表格处理部分的变量可以具有报表模块作用域。任何其它的实例化的变量具有函数模块作用域。
对一个标识符的引用导致该标识符被它的值所替换。 如果对一个变量的引用没有相应的值,或一个函数调用没有返回值,则该引用被一个空串 替换。
以下章节描述了如何定义和引用变量,还描述了不同的变量类型以及如何使用 它们。
有 3 种方法定义 Net.Data 宏中的变量
定义在 Net 宏中使用的一个变量的最简单方法是使用 DEFINE 语句。其专用于 Net.Data 的语法:
%DEFINE variable_name="variable value"
%DEFINE variable_name={ variable value on multiple
lines of text %}
这里,variable_name 您给出的变量名称。变量名必须以一个字母或下划线开头,可以包含 任何字母数字字符或下划线。所有变量名都区别大小写,除了 N_columnName 和 V_columnName,它们是表格变量。
如果字符串中包含引号,则应该使用两个连续的引号。 仅有两个连续引号的字符串是一个空串。
%DEFINE HI="say ""hello""" %DEFINE reply="hello" %DEFINE empty=""
显示时,变量 HI 是 say "hello",变量 reply 是 hello, 而变量 empty 是空的。
如果要用一个 DEFINE 语句定义几个变量,可以采用 DEFINE 模块
%DEFINE{
variable1="value1"
variable2="value2"
variable3="value3"
variable4="value4"
%}
此例子使用标准 HTML 表标记来定义应该变量:
<INPUT NAME="variable_name" TYPE=...>
或
<SELECT NAME="variable_name">
这里,variable_name 是变量的名称,这个变量的值是由从表中接收到的输入决定的。请参 阅"HTML 表"以获取关于如何在一个 Net.Data 宏中使用这个变量类型定义 的例子。
从 INPUT 或 SELECT 语句接收的变量值将覆盖在 Net.Data 中用 DEFINE 设置的 变量值。
可以作为 RUL 调用 Net.Data 宏,并且在这个 URL 中包含传送给 Net.Data 的变量,例如用户标识符。例如:
http://www.ibm.com/cgi-bin/db2www/stdqry1.mac/input?field=custno
这里,增加的数据 field=custno是以与表数据相同的方式由 Net.Data 接收的,并以相同的方式被处理。
在 Net.Data 宏中,变量是通过在 $( 和 ) 之间指定变量名 来引用的(IF 条件模块除外,在那儿只使用变量名)。 例如:
$(variableName) $(homeURL)
当 Net.Data 找到一个变量引用时,此变量引用被它的值所替换。 不允许循环引用。例如,以下的 DEFINE 语句是不允许的,在变量被引用、 求最后值时会产生一个错误:
%DEFINE a="$(b)" %DEFINE b="$(a)"
可以将变量作为 HTML 的一部分来使用。例如,如果定义了变量 homeURL 如下:
%DEFINE homeURL="http://www.ibm.com/"
就可以以 $(homeURL) 形式引用主页,并按如下方法创建一个锚引用:
<A href="$(homeURL)">Home page</A>
可以在一个 Net.Data 宏中的任何部分引用变量。 如果在引用时变量尚未定义,则 Net.Data 将定义这个变量,并将其初始值赋为空值。当对 Net.Data 宏进行语法分 析时,如果发现一个变量引用,则先对其求值,然后将这个变量的当前值直接插入。
条件变量确定一个变量是否存在,并且不为空值。 如果确实存在,则将第一个值赋给它,否则将第二个值赋给它。 条件变量的语法是:
varA = varB ? "value_1" : "value_2"
如果 varB 被定义,varA="value_1", 否则 varA="value_2"。这等价于使用一 个 IF 模块:
%IF ( varB )
varA = "value_1"
%ELSE
varA = "value_2"
%ENDIF
请参阅"列表变量" 以获取条件变量与列表变量一起使用的一个例子。
可以引用存在于 Net.Data 在其下运行的进程 Net.Data 中的环境变量,例如:
客户为 @DTW_rGETENV("SERVER_NAME"),
其输出如下:
The HTTPD server is IBM Internet Connection Server/4.1
请参阅 Net.Data Reference Guide(Net.Data 参考指南) 以获取 关于 @DTW_GETENV 和 @DTW_rGETENV 函数的更多信息。
可以使用可执行变量的功能从一个变量引用来调用其它程序。 可执行变量可以在 Net.Data 宏中通过以下方法来定义:
%DEFINE runit=%exec "testProg"
Net.Data 在 Net.Data 初始化文件中的 EXEC_PATH 中查找可执行程序 。请参阅 "EXEC_PATH" 以获取有关细节。
当对 Net.Data 宏中的变量 runit 作一个有效的变量引用时,就执行程序 testProg。 一个简单的例子是从另一个变量定义引用一个可执行变量:
%DEFINE date=%exec "date" %DEFINE dateRpt="今天是 $(date)"
不管 $(dateRpt) 出现在 Net.Data 宏中 的什么地方,Net.Data 都返回:
今天是 Tue 11-07-1995
执行变量永远不会被设置为它所调用的可执行程序的输出值。 使用前面的例子,日期的值为空(NULL)。 如果在 DTW_ASSIGN 函数调用中用它把值赋给另一个变量,则在赋值以后新 变量的值也为空(NULL)。 执行变量的唯一目的是调用它所定义的程序。 还可以通过 用变量定义中的程序名指定参数名,来将参数传递给要执行的程序。 在 此例中,distance 和 time 的值被传递给程序 calcMPH。
%DEFINE mph=%exec "calcMPH $(distance) $(time)"
下面的例子将系统日期作为 HTML 报表的一部分返回:
%DEFINE database="celdial"
%DEFINE tstamp=%exec "date"
%FUNCTION(DTW_SQL) myQuery() {
SELECT CUSTNO,CUSTNAME from dist1.customer
%REPORT{
%ROW{
<A HREF="/cgi-bin/db2www/exmp.mac/report?value1=$(V1)&value2=$(V2)">
$(V1) $(V2) </A> <BR>
%}
%}
%}
%HTML(report){
<H1>Report made: $(tstamp) </H1>
@myQuery()
%}
每个报表都显示时间以便跟踪。 对这个例子,还在锚引用中放置了 客户号和名称,供另一个 Net.Data 宏使用。 单击报表中的任何客户都将调用 exmp.mac Net.Data 宏 ,并将编号和名称传递给这个 Net.Data 宏。
隐藏变量用于隐藏一个变量的实际名称,以防止使用 Web 浏览器察看 HTML 源文 件的其他人员看见这些名称。
%HTML(INPUT) {
<FORM ...>
<P>Select fields to view:
<SELECT NAME="Field">
<OPTION VALUE="$$(name)"> Name
<OPTION VALUE="$$(addr)"> Address
.
.
.
</FORM>
%}
%DEFINE{
name="customer.name"
addr="customer.address"
%}
%FUNCTION(DTW_SQL) mySelect() {
SELECT $(Field) FROM customer
%}
.
.
.
当在 Web 浏览器中显示 HTML 表时,$$(name) 和 $$(addr) 分别被替换成 $(name) 和 $(addr),这样就不需要在 HTML 表中出 现实际的表格名称和列名。没有任何办法告诉实际变量名是隐藏的。 当客户提交这个表时,调用 HTML(REPORT) 模块。 当 @mySelect() 调用 FUNCTION 模块时,SQL 语句中的 $(Field) 被替换成 SQL 查询中的 customer.name 或 customer.addr。
列表变量允许您构建值的定界字符串。当要构建一个具有多个项目的 SQL 查询时 (象某些 WHERE 或 HAVING 语句一样),它们特别有用。 列表变量的 语法是:
%LIST " value_separator " variable_name
其中的空格是必须的。 我们建议在大多数情况中在值分隔符之前或 之后有一个空格。大部分查询使用布尔或 数学运算符(例如,AND、OR 或 >) 作为值分隔符。 下面的例子说明了条件、隐藏和列表变量的用法:
%HTML(INPUT){
<FORM METHOD="POST" ACTION="/cgi-bin/db2www/example2.mac/report">
<H2>Select one or more cities:</H2>
<INPUT TYPE="checkbox" NAME="conditions" VALUE="$$(cond1)">Sao Paola<BR>
<INPUT TYPE="checkbox" NAME="conditions" VALUE="$$(cond2)">Seattle<BR>
<INPUT TYPE="checkbox" NAME="conditions" VALUE="$$(cond3)">Shanghai<BR>
<INPUT TYPE="submit" VALUE="Submit Query">
</FORM>
%}
%DEFINE{
DATABASE="custcity"
%LIST " OR " conditions
cond1="Sao Paolo"
cond2="Seattle"
cond3="Shanghai"
whereClause=Conditions ? "WHERE $(conditions)" : ""
%}
%FUNCTION(DTW_SQL) mySelect(){
SELECT name, city FROM citylist
$(whereClause)
%}
%HTML(REPORT){
@mySelect()
%}
在 HTML 表中,如果没有选择任何框,则 conditions 为空,因此查询中 的 whereClause 也为空。 否则,whereClause 中包含了选定的 值,值之间用 OR 分隔。 例如,如果选择了所有这三个城市,则 SQL 查询为:
SELECT name, city FROM citylist WHERE cond1='Sao Paolo' OR cond2='Seattle' OR cond3='Shanghai'
此图显示选定城市 Seattle,这得到此 SQL 查询:
SELECT name, city FROM citylist WHERE cond1='Seattle'
表格变量定义相关数据的集合。它包含一个相同记录或列的数组,和一个在每 一行描述字段的列名的数组。 在 Net.Data 宏中可以使用如下语句定义一个 表格:
%DEFINE myTable=%TABLE(30)
TABLE 后面的数值限制了这个表格可以包含的行数。 要指定一个对行数没有 限制的表格,使用缺省值或指定 ALL,如下例所示:
%DEFINE myTable2=%TABLE %DEFINE myTable3=%TABLE(ALL)
可以通过对变量名的引用,在函数之间传递一个表格。 还可以在一 个函数的 REPORT 块中引用表格中的个别元素。表格变量通常用于一个 SQL 函数的输出,或用于一个报表的输入,但也可以将它们作为 IN、 OUT 或 INOUT 参数传递给任何非 SQL 函数。 表格只能作为 OUT 参数传递给 SQL 函数。
表格中的列名和字段值可以当作起始下标为 1 的数组元素来存取, 而不同于标准的 C 和 C++ 语言(其起始数组下标为 0)。
一个表格变量的定义将引起 Net.Data 隐式地定义两组变量,
您可以使用这两组变量来引用表格的列名和字段内容。 这些隐式变量中的其中一
组是在 Net.Data 宏中 FUNCTION 模块的 REPORT 模块中引用的;另一组是
在语言环境调用的程序中引用的。 不能在 Net.Data 宏的其它任何模块中
引用这些变量。
| N1, N2, ..., Nj | 第 j 列的名称。 |
| N_columnName | 此值是 columnName 的值。 |
| NLIST | N1 至 Nj 的所有列名的一个连接。 |
| V1, V2, ..., Vj | 包含当前行中第 j 列的值。 |
| V_columnName | 包含当前行中第 j 列的值。 |
| VLIST | 当前行中从 V1 至 Vj 的所有字段值的一个连接。 |
| ROW_NUM | 包含当前行的行号。 |
| NUM_COLUMNS | 包含表格中的列数。 |
| TOTAL_ROWS | 包含表格中的行数。 |
Net.Data 提供许多函数,您可以发现它们在您的 Web 应用程序中是 很有用的。 写您自己的函数也很容易。
您可以定义自己的函数,或使用 Net.Data 的函数库。 对于非 Net.Data 库中的函数,应该使用 FUNCTION 模块将它定义到 Net.Data 宏。 细节在Net.Data 语言环境指南中说明。其语法如下:
%FUNCTION(type) function-name([usage parameter, ...]) [RETURNS(return-var)] {
executable-statements
[report-block]
[message-block]
%}
标识初始化文件中配置的语言环境。语言环境调用专用的语言处 理器(它处理可执行语句),并在 Net.Data 和语言处理器之间提供了一个标准接 口。
与 Net.Data 一起提供了几种缺省的语言环境。
这是 FUNCTION 模块名。FUNCTION 模块是通过在 Net.Data 宏的 其它地方引用其名称来执行的,前面要有一个 at (@) 符号。 FUNCTION 模块的执行是一个函数调用。 请参阅“调用函数”以获取细节。
可以存在多个同名的 FUNCTION 模块。 它们必须具有相同的参数表。 当这个函数被 调用时,按照在 Net.Data 宏中定义的顺序执行所有同名的 FUNCTION 模块。
局部变量的名称,它们的值将被在函数调用中指定的相应参数的值来替换。 可执 行语句或报表模块的参数引用,如 $(parm1),将被参数的实际值替换。 另外,参数被传递给语言环境,并且可以通过那种语言环境的自然语法或作为环 境变量被可执行语句存取。 在 FUNCTION 模块以外,参数变量引用无效。
也可以传递指定类型的函数调用中的隐式参数。 必须在初始化文件中的 ENVIRONMENT 语句中定义参数。
应该在最外层的 Net.Data 宏中、并且在它们被调用之前定义函数。
使用 at (@) 字符,后面跟一个 FUNCTION 模块名来从 Net.Data 宏调用 一个函数:
@function_name([ argument,... ])
当调用 FUNCTION 模块时,Net.Data 将作如下处理:
在一个函数调用中使用和修改 FUNCTION 模块中变量的规则可以总结如 下:
当对 MESSAGE 模块和 REPORT 模块的处理完成后,使用函数调用的值来替换 Net.Data 宏中的函数调用。
存储过程简单地称为一个 SQL 过程。 通过把已编译的 SQL 语句与数据库服务器一起保存,存储过程提供了较高的性能 和完整性。
存储过程可以使用用于大部分平台的这些数据类型:
| BLOB | DOUBLEPRECISION | SMALLINT |
| CHAR | FLOAT | TIME |
| CLOB | INTEGER | TIMESTAMP |
| DATE | GRAPHIC | VARCHAR |
| DBCLOB | LONGVARCHAR | VARGRAPHIC |
| DOUBLE | LONGVARGRAPHIC |
|
请参阅数据库文档,以获取有关这些数据类型的更多信息。 Net.Data 可能不支持由数据库支持的所有数据类型。 请参阅 Net.Data 参考指南 的附录以获取细节。
以下是调用一个名为 stored_proc1 的存储过程的例子:
%FUNCTION(DTW_SQL) stored_proc1 ( IN float(7,2) arg1,
INOUT SMALLINT arg2,
OUT VARCHAR(9) retval)
RETURNS (RESULT) {
CALL statsrpt
%}
%HTML(REPORT) {
@stored_proc1(arg1, arg2, retval)
.
.
.
%}
存储过程的名称为 statsrpt,它是由 CALL 语句调用的。 函数 stored_proc1 是调用存储过程的函数名称。
MESSAGE 模块根据函数调用的成功与失败,确定在这个函数调用以后如何进行 处理,并允许您将信息显示给函数的调用者。
Net.Data 为每个函数调用设置 RETURN_CODE,它是一个隐式变量。 RETURN_CODE 被设置为对语言环境的调用的返回码。 当函数调用完成时, MESSAGE 模块使用 RETURN_CODE 的值来确定如何进行处理。 一个 MESSAGE 模块中包含了一系列消息语句,每个语句指定了一个返回码值、消 息文本和采用的操作。 MESSAGE 模块的语法如 下:
>>-%message--{-------------------------------------------------->
+--------------------------------------------------------+
v |
>--------------------------------------------------------------->
+-| 返回码说明 |--:--| 消息文本说明 |--| 操作说明 |--+
>-%}-----------------------------------------------------------><
返回码说明
|----DEFAULT---------------------------------------------------|
|- +DEFAULT---|
|- -DEFAULT---|
+-------数值--+
|---|
+-+-+
消息文本说明
+-------------+
v |
|-----"-------------------"------------------------------------|
| |-字符串---| |
| |-变量引用-| |
| +-函数调用-+ |
| +-------------+ |
| v | |
+-{-------------------%}--+
|-字符串---|
|-变量引用-|
+-函数调用-+
操作说明
|--:----EXIT---------------------------------------------------|
+-CONTINUE-+
一个 MESSAGE 模块可以具有全局或者本地作用域。如果 MESSAGE 模 块是在 FUNCTION 模块中定义的,则它的作用域对该 FUNCTION 模块是 本地的。 如果它是在外宏层定义的,则具有全局作用域,并且对 Net.Data 宏中 执行的所有函数调用都是活动的。如果您定义了多个全局 MESSAGE 模 块,则最后一个定义的模块是活动的。
Net.Data 使用这些规则处理来自函数调用的 RETURN_CODE:
这里是一个 Net.Data 宏的部分例子,其中有一个全局 MESSAGE 模 块和一个函数的 MESSAGE 模块。
%{ 全局消息模块 %}
%MESSAGE {
-100 : "Return code -100 message" : exit
100 : "Return code 100 message" : continue
+default : {
This is a long message that spans more
than one line. You can use HTML tags, including
anchors and forms, in this message. %} : continue
%}
%{ local message block inside a FUNCTION block %}
%FUNCTION(DTW_REXX) my_function() {
%EXEC { my_command.cmd %}
%MESSAGE {
-100 : "Return code -100 message" : exit
100 : "Return code 100 message" : continue
-default : {
This is a long message that spans more
than one line. You can use HTML tags, including
anchors and forms, in this message. %} : exit
%}
如果 my_function() 返回 RETURN_CODE 为 50,则 Net.Data 以下列顺序处理错误:
现在 Net.Data 找到了一个匹配,它将这个消息文本发送到 Web 浏览器,并 检查请求的操作。 因为指定了继续,所以在打印信息正文之后, Net.Data 继续处理 Net.Data 宏。
例如,如果一个宏调用 my_functions() 5 次,并在处 理例子中的 MESSAGE 模块时发现错误 100,则程序的输出可以类似这样 :
. . . 11 May 1997 $245.45 13 May 1997 $623.23 19 May 1997 $ 83.02 return code 100 message 22 May 1997 $ 42.67 Total: $994.37
请参阅附录 A. "动态查询的例子"以获取本地局部的另一个例子。
Net.Data 能让您很容易地在应用程序用户的浏览器上表达标准 HTML。以下模块显示怎样在 Net.Data 宏中格式化 HYML。
调用自一个 HTML 模块的 HTML 模块和函数是 Net.Data 宏模块以生成对浏览器的 HTML 的输出。 当 Net.Data 被调用时,必须指定一个 HTML 模块。这个块中包含的内容控制了 Net.Data 调用的其它部分。
任何有效的 HTML 都可以出现在 HTML 模块中。另外,INCLUDE 语句 、函数调用和变量引用也可以出现在 HTML 模块中。Net.Data 宏中的 HTML 模块的一个公共使用由此例子 Net.Data 宏显示:
%DEFINE DATABASE="MNS96"
%HTML(INPUT){
<H1>硬件查询表</H1>
<HR>
<FORM METHOD="POST" ACTION="/cgi-bin/db2www/equiplst.mac/report">
<dl>
<dt>您要列出哪种硬件?
<dd><input type="radio" name="hdware" value="MON" checked>
监视器
<dd><input type="radio" name="hdware" value="PNT">定点设备
<dd><input type="radio" name="hdware" value="PRT">打印机
<dd><input type="radio" name="hdware" value="SCN">扫描仪
</dl>
<HR>
<input type="submit" value="提交">
</FORM>
%}
%FUNCTION(DTW_SQL) myQuery() {
SELECT MODNO, COST, DESCRIP FROM EQPTABLE WHERE TYPE=$(hdware)
%REPORT{
<B>Here is the list you requested:</B><BR>
%ROW{
<HR>
$(N1): $(V1) $(N2): $(V2)
<P>
$(V3)
%}
%}
%}
%HTML(REPORT){
@myQuery()
%}
您可以这样地从一个锚引用来调用 Net.Data 宏:
<a href="http://www.ibm.com/cgi-bin/db2www/equiplst.mac/input">List of hardware</a>
当应用程序用户单击此引用时,Net.Data 被调用,并且 Net.Data 分 析 Net.Data 宏文件。当它到达调用处(在此情况下是 HTML(INPUT) 模 块)所指定的 HTML 模块时,它开始处理模块中的文本。由 Net.Data 识 别为 Net.Data 宏语言结构的任何东西都被假定为 HTML,并被发送给浏 览器显示。
在作出选择并且按了“提交”按钮之后,HTML FORM 元素的 ACTION 部分被执行,它指定对 Net.Data 宏的 HTML(REPORT) 模块的调用。然 后,HTML(REPORT) 模块象 HTML(INPUT) 模块一样被处理。 queryHardware() 函数调用上的所有数据作为 HTML 被输出至浏览器。
然后,queryHardware() 函数调用被处理,它依次调用 SQL FUNCTION 模块。在 SQL 语句中的$(hdware) 变量引用被以输入格式 返回的值替换之后,查询开始执行。在此点,Net.Data 再次开始发 送 HTML 至浏览器,根据 REPORT 模块中指定的 HTML 来显示查询结 果。
在 REPORT 模块处理完成之后,我们再次返回 HTML(REPORT) 模块, 并通过发送在 queryHardware() 函数调用之后指定的剩余 HTML 来结束处 理。
每次 Net.Data 调用只处理一个 HTML 模块。但是,通过使用 HTML 锚引用和格式,人们可以很容易地使用一个应用程序来启动另一个 HTML 模块上的另一个 Net.Data 调用,一切由您控制。
Report 模块用于格式化和显示来自 FUNCTION 模块的数据输出。尽管输出中可以指定 HTML 标记、宏变量引用和函数调用的组合,但这种输出信 息通常是表格数据。 在 Report 模块上可以指定一个表名,但是这并不需要。如果没有指定 表名,则所使用的表数据是 FUNCTION 模块的参数表中的第一个输出表 格。如果在 FUNCTION 模块中没有指定表格,则使用缺省表数据。
Report 模块由三个部分组成,每个部分都是可选的:
如果您不希望显示从 ROW 模块输出的任何表格,只须让它为空。
当 Net.Data 处理 FUNCTION 模块时,对语言环境作出调用,数据被 返回。然后 Net.Data 处理 Report 模块。
在 Report 模块中,Net.Data 提供几个隐式定义的变量,让您访问 Net.Data 宏结果表中的数据。这些变量在表 1 中描述。关于附加细节,请参阅参考指南中的 Report 变量节。
标题和脚注信息如 REPORT 模块中的一样不是显式指定的。Net.Data 简单地将 ROW 模块之前找到的任何东西作为标题信息处理,而将 ROW 模块之后找到的任何东西作为脚注信息处理。因为带 HTML 模块,所以 Net.Data 宏处理器将标题、ROW 和脚注模块中的任何东西作为 HTML 对 待,并将该数据发送至浏览器。 您还可以包含函数和变量。
要避免报表,可以省略 Report 模块并设置 DTW_DEFAULT_REPORT 为 NO。如果您将它设置为 YES,则用缺省格式显示一个报表,例如:
SHIPDATE | RECDATE | SHIPNO | ------------------------------------- 25/05/1997 | 30/05/1997 | 1495194B | ------------------------------------- 25/05/1997 | 28/05/1997 | 2942821G | -------------------------------------
设置 DTW_HTML_TABLE 为 YES 以使用 HTML 表格替换缺省报表的预 格式化文本。
下面的例子显示了如何使用特殊变量和 HTML 标记来定制报表格式。 它显示来自表格 CustomerTbl 的名称、电话号码和传真号码:
%FUNCTION(DTW_SQL) custlist() {
SELECT Name, Phone, Fax FROM CustomerTbl
%REPORT{
<I>Phone Lookup Results:</I>
<BR>
=====================
%ROW{
Name: <B>$(V1)</B>
Phone: $(V2)
Fax: $(V3)
------------------------------
%}
Total records retrieved: $(ROW_NUM)
%}
%}
结果报告在 Web 浏览器中看起来象这样:
Phone Query Results: ==================== Name: Doen, David Phone: 422-245-1293 Fax: 422-245-7383 ------------------------------ Name: Ramirez, Paolo Phone: 955-768-3489 Fax: 955-768-3974 ------------------------------ Name: Wu, Jianli Phone: 525-472-1234 Fax: 525-472-1234 ------------------------------ Total records retrieved: 3
Net.Data 通过以下步骤生成报表:
DB2 在号码递增的平台上支持大型对象 (LOB)。 检查您的 DB2 文档看它是否支持 LOB。DB2 支持的三种 LOB 类型是:
当一个查询返回一个 LOB 时,Net.Data 将它保存在 HTML_PATH 配 置变量所指定的目录中。 使用 LOB 时应该考虑系统限制,因为它们会快速地消耗资源。 有些 LOB,如声频文件,需要有特殊的硬件和软件。
LOB 通常在头几个字节中包含一个文件特征标记,以此指定文件包含的信息类 型。如果 Net.Data 识别到一个 LOB,则其扩展名添加至临时文件和表 示其名称的 Net.Data 宏变量。如果没有 Report 模块,则 CLOB 将 .txt 扩展名添加进去。这些是可识别的 LOB 格式:
不能识别其他文件类型,因而不支持它们。对任何大型对象,都不支持 UPDATE 和 INSERT SQL 语句。 下面的第一个例子以直接插入的方式显示了一个图片。 在第二个例子中,应用程 序用户必须单击文件名,来调用察看器。
<IMG SRC="/tmplobs/filename"> <A HREF="/tmplobs/filename">filename</A>
这是一个在应用程序中使用 .WAV 文件的例子。此文件类型不能被 Net.Data 识别,因此 EXEC 变量被用于将扩展名添加至文件。
%DEFINE{
docroot="/usr/lpp/internet/server_root/html"
rename=%EXEC "rename $(docroot)$(V3) $(docroot)$(V3).wav"
%}
%FUNCTION(DTW_SQL) queryData() {
SELECT Name, IDPhoto, Voice FROM RepProfile
%REPORT{
<P>Here are the images you selected:<P>
%ROW{
$(rename)
$(V1) Voice sample <IMG SRC="$(V2)">
<A HREF="$(V3.wav")>Voice sample</A><P>
%}
%}
%}
%HTML(REPORT){
@queryData()
%}
queryData 函数返回以下 HTML:
<P>Here are the images you selected:<P> Kinson Yamamoto <IMG SRC="/tmplobs/p2345n1.gif"> <A HREF="/tmplobs/p2345n2.wav">Voice sample</A><P> Merilee Lau <IMG SRC="/tmplobs/p2345n3.gif"> <A HREF="/tmplobs/p2345n4.wav">Voice sample</A><P>
此 Report 模块使用隐式表格变量 V1、V2 和 V3。
不是所有的 Web 浏览器都能支持图形和声音。可能需要特殊的硬件和软件 (例如语音卡和驱动程序)以支持这里描述的功能。