IBM Books

Net.Data 程序设计指南


开发 Net.Data 宏

本章介绍 Net.Data 宏的不同组成部分,以及它们如何在一个应用程序中一起工作的。


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 模块:输入    ************************%}
%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() 函数调用。 变量 inputresult 被 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 宏中的变量。 另外,还可以将这些变量从宏传递给环境变量,或从环境变量传递回宏。 Net.Data 令牌 ,例如变量名和引用字符串,可以包含多达 64KB 数据。对于 OS/400,最大尺寸取决于该 系统。

宏变量分成如下类型:

一个标识符(它是一个变量或函数调用)被说明或实例化时,成为可见的 ( 即,可引用的)。 标识符在其中是可见的那个区域,称为它的作用域。有五类作用域:

以下章节描述了如何定义和引用变量,还描述了不同的变量类型以及如何使用 它们。

定义变量

有 3 种方法定义 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 源文 件的其他人员看见这些名称。

列表变量

列表变量允许您构建值的定界字符串。当要构建一个具有多个项目的 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 宏的其它任何模块中 引用这些变量。

表 1. 报表变量
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 宏函数

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]
%}

type

标识初始化文件中配置的语言环境。语言环境调用专用的语言处 理器(它处理可执行语句),并在 Net.Data 和语言处理器之间提供了一个标准接 口。

与 Net.Data 一起提供了几种缺省的语言环境。

function-name

这是 FUNCTION 模块名。FUNCTION 模块是通过在 Net.Data 宏的 其它地方引用其名称来执行的,前面要有一个 at (@) 符号。 FUNCTION 模块的执行是一个函数调用。 请参阅“调用函数”以获取细节。

可以存在多个同名的 FUNCTION 模块。 它们必须具有相同的参数表。 当这个函数被 调用时,按照在 Net.Data 宏中定义的顺序执行所有同名的 FUNCTION 模块。

usage
IN、OUT 或 INOUT。这表示参数是传递到 FUNCTION 模块、从 FUNCTION 传 递出来、还是既有传入又有传出。 所选择的 usage 类型适用于参数表中所有的后 继参数,直到更改为其它 usage 类型为止。 缺省类型是 IN。

parameter

局部变量的名称,它们的值将被在函数调用中指定的相应参数的值来替换。 可执 行语句或报表模块的参数引用,如 $(parm1),将被参数的实际值替换。 另外,参数被传递给语言环境,并且可以通过那种语言环境的自然语法或作为环 境变量被可执行语句存取。 在 FUNCTION 模块以外,参数变量引用无效。

也可以传递指定类型的函数调用中的隐式参数。 必须在初始化文件中的 ENVIRONMENT 语句中定义参数。

return-var
在 RETURNS 关键字后面指定此参数。 它标识了一个特殊的 OUT 参数。 返回变量的值被赋给函数调用,并在 Net.Data 宏处理中替换这个函数调 用。如果不指 定 RETURNS 语句,那么如果从调用中返回到语言环境的返回码是 0,则函数调用 的值是空串,否则函数调用的值是返回码。

executable-statements
在变量被替换、函数被处理以后,这些语句将被传递给指定的语言环境执行。 每种语言环境都以各自不同的方法处理这些语句。 请参阅 "可执行变量",以获取有关指定可执行语句或调用可执行程序的更多细节。

report-block
请参阅 "Report 模块"

message-block
请参阅 "消息模块"

应该在最外层的 Net.Data 宏中、并且在它们被调用之前定义函数。

调用函数

使用 at (@) 字符,后面跟一个 FUNCTION 模块名来从 Net.Data 宏调用 一个函数:

@function_name([ argument,... ])

function_name
这是要调用的 FUNCTION 模块名。如果这个函数不是一个内部函数,则必须已 经在 Net.Data 宏中定义。

argument
这是一个已定义的变量或一个字面量字符串。 函数调用中的变 量必须与 FUNCTION 模块中的参数相匹配,在 FUNCTION 模块的生存期中,每个参 数都被赋予了相应变量的值。 变量的个数和类型必须与相应的参数相同。

当调用 FUNCTION 模块时,Net.Data 将作如下处理:

  1. Net.Data 将函数调用中的所有变量与来自 FUNCTION 模块的参数相匹配。 如 果变量的个数或用法类型不匹配,则发生一个错误。

  2. 从所有在 FUNCTION 模块中指定的函数参数、以及在初始化文件中的 ENVIRONMENT 语句指定的变量,创建了一系列变量。 在这个步骤中有两个不同的变量集合:全局集,由所有到目 前为止定义的变量组成;局部集,为本函数创建的变量。 全局变量在 "Net.Data 宏变量" 中讨论。

  3. 通过先在局部变量集中查找变量,然后在全局变量集中进行查找的方法,将 FUNCTION 模块的可执行文本中的变量引用替换为变量的实际值。 如果在两个集合 中都存在这个变量(例如,一个被指定为一个函数参数,另一个在先前的 DEFINE 中),则局部集合中的优先。

  4. 处理 FUNCTION 模块的可执行文本中的函数调用。 函数调用的上下文在可执行文本中与 Net.Data 无关。 例如,如果函数调用在可执行文本中具有条件逻辑,则即使它与您指定的条件不 匹配,Net.Data 仍将处理此函数调用。

  5. 局部集合中的变量与可执行语句的文本一起被传递到语言环境。 语言环境负 责将 IN 和 INOUT 变量传递到语言处理器、解释可执行语句或调用语言处理器执 行这些语句、并且当程序执行后检索从语言处理器返回的 OUT 或 INOUT 变量。

  6. 当语言环境返回到 Net.Data 时,可以从参数表中获取任何 OUT 或 INOUT 参数,并使用它们的值来替换局部或全局变量集合中相应变量的值。 如 果有一个 RETURNS 语句,这个返回变量的值将与 FUNCTION 模块信息一起保存, 以便可以用于替换 Net.Data 宏扩充中的函数调用。

在一个函数调用中使用和修改 FUNCTION 模块中变量的规则可以总结如 下:

当对 MESSAGE 模块和 REPORT 模块的处理完成后,使用函数调用的值来替换 Net.Data 宏中的函数调用。

调用存储过程

存储过程简单地称为一个 SQL 过程。 通过把已编译的 SQL 语句与数据库服务器一起保存,存储过程提供了较高的性能 和完整性。

存储过程可以使用用于大部分平台的这些数据类型:

表 2. 存储过程数据类型
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

一个节的关键字,它定义了一组返回码、相应的 消息以及在函数调用返回时 Net.Data 所要采用的操作。

返回码说明:

一个正整数或负整数。如果 Net.Data RETURN_CODE 变量的值与 返回码说明值相匹配,则使用消息语句中的剩余信息来处理这个函数调用。 您 也可以为返回码指定消息,而不需要在 $MESSAGE 模块中特别输入。

DEFAULT

一个用于指定缺省消息代码的关键字。如果 RETURN_CODE 不等于 0,并且没有 指定精确匹配,则使用此消息语句中的消息来处理函数调用。

+DEFAULT

一个用于指定缺省的负消息代码的关键字。 如果 RETURN_CODE 小于 0,并且没有 指定精确匹配,则使用此消息语句中的消息来处理函数调用。

-DEFAULT

一个用于指定缺省的正消息代码的关键字。 如果 RETURN_CODE 大于 0,并且没有 指定精确匹配,也没有指定 +DEFAULT (用于 RETURN_CODE 大于 0 情况) 或 -DEFAULT (用于 RETURN_CODE 小于 0 的情况) 的值,则使用此消息语 句中的消息来处理函数调用。

数值

用于指定在处理期间出现的错误和警告的消息代码。从 0 到 9 的一串数字。

消息文本说明

当 RETURN_CODE 与此消息的消息语句中的返回码值相匹配时,要发送 到 Web 浏览器去的一个字符串。

字符串

字母、数字和标点符号(除制表符、换行符或空格外)的任意序列。

变量引用

返回一个先前定义的变量的值,用 $ 和 () 来指定。 例如: 如果 VAR = 'abc',那么 $(VAR) 将返回值 'abc'。

函数调用

用指定的参数调用一个或多个先前定义的 FUNCTION 模块。

操作说明:

当 RETURN_CODE 与此消息的消息语句中的返回码值相匹配时 Net.Data 要 执行的操作。

EXIT

这个关键字指定了:当发生与指定的消息返回码相应的错误与警告时,立即 退出这个宏。

CONTINUE

这个关键字指定了:当发生与指定的消息返回码相应的错误与警告时,继续 进行处理。

一个 MESSAGE 模块可以具有全局或者本地作用域。如果 MESSAGE 模 块是在 FUNCTION 模块中定义的,则它的作用域对该 FUNCTION 模块是 本地的。 如果它是在外宏层定义的,则具有全局作用域,并且对 Net.Data 宏中 执行的所有函数调用都是活动的。如果您定义了多个全局 MESSAGE 模 块,则最后一个定义的模块是活动的。

Net.Data 使用这些规则处理来自函数调用的 RETURN_CODE:

  1. 检查本地 MESSAGE 模块的精确匹配,按所指定的那样退出或继续下去。

  2. 如果 RETURN_CODE 非 0,则根据 RETURN_CODE 的符号,检查本地 MESSAGE 模块的+default-default,按所指定的那样退出或继续下去。

  3. 如果 RETURN_CODE 非 0,则检查本地 MESSAGE 模块的缺省值,按所指定的那样退出或继续下去。

  4. 检查全局 MESSAGE 模块的精确匹配,按所指定的那样退出或 继续下去。

  5. 如果 RETURN_CODE 非 0,则根据 RETURN_CODE 的符号,检查全局 MESSAGE 模块的+default-default,按所指定的那样退出或继续下去。

  6. 如果 RETURN_CODE 非 0,则检查全局 MESSAGE 模块的缺省值,按所指定的那样退出或继续下去。

  7. 如果 RETURN_CODE 非 0,发出 Net.Data 内部缺省消息并退出。

这里是一个 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 以下列顺序处理错误:

  1. 在本地 MESSAGE 模块中检查精确匹配。(没有。)

  2. 在本地 MESSAGE 模块中检查+default。(没有。)

  3. 在本地 MESSAGE 模块中检查default。 (没有。)

  4. 在全局 MESSAGE 模块中检查精确匹配。 (没有。)

  5. 在全局 MESSAGE 模块中检查+default。 (有一个。)

现在 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. "动态查询的例子"以获取本地局部的另一个例子。


在宏中生成 HTML

Net.Data 能让您很容易地在应用程序用户的浏览器上表达标准 HTML。以下模块显示怎样在 Net.Data 宏中格式化 HYML。

HTML 模块

调用自一个 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 模块

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 通过以下步骤生成报表:

  1. 在报告的开头打印 Phone Query Results: 一次。

  2. 为所检索到的每一行分别给出变量 V1V2V3 以 Name、Phone 和 Fax 的值。

  3. 为了增加可读性,在检索到的每行之后画一条横线。

  4. 在报表的结尾打印字符串 Total records retrieved:ROW_NUM 的值。

使用大型对象

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 浏览器都能支持图形和声音。可能需要特殊的硬件和软件 (例如语音卡和驱动程序)以支持这里描述的功能。


[ 页的顶部 | 上一页 | 下一页 | 内容表 | 索引 ]