さて、前述のCGIが目的とするHTMLを出力するにあたって、CGI001
で行ったようにRPGの内部配列として
保管しておいて、それを出力すればよいのですが、今度は静的なHTMLではなく、変数の値を埋め込まなければ
ならないわけですから、値を埋め込みたい位置にはフィールドの名前を入れておいて、そこに値を埋め込みたいと
思います。
例えば フィールド SHCODE
の値を埋め込みたい位置には「SHCODE」
と書いておきます。
すると出力したいHTML は次のようになるはずです。
埋め込みたい位置がフィールド名になっていることを注意深く眺めてください。
このHTMLは値の埋め込みの「元」となるわけですが、このような目的のためのHTMLを
HTMLテンプレート と呼びます。
それでは下記のHTMLテンプレートで使用しているHTMLタグとその構造について、簡単に説明していきましょう。
<html>〜</html>
には大きく分けて2つのブロックが存在します。
ブラウザに表示させる内容 を記述した(いわゆるコンテンツ)ブロック(<body>〜</body>
)と、
表示されない情報 を記述したブロック(<head>〜</head>
)です。
まず表示されない情報である<head>
に含まれるものから見ていきましょう。
<meta>
は その.htmlファイルに関する情報の定義 に使用します。
http-equiv="Content-Language" content="ja"
は、日本語のコンテンツ であることの宣言、
http-equiv="Content-Type" content="text/html; charset=shift_jis"
は、これがhtmlに準じたテキストファイルで、文字コードは シフトJIS であることを定義しています。
漢字やカナを記述した.htmlの場合、これらが宣言されていないとブラウザ側で文字化け を起こす場合が
ありますので、必ず記述しておきます。
なお、JISコードで記述した場合は charaset="〜"
の部分を『iso-2022-jp』に、EUCの場合は『euc-jp』とします。
(Windowsで.htmlを作成する場合は基本的にシフトJISですので『shift_jis』です。)
<title>〜</title>
はその.htmlを単独でブラウザに表示したときのウィンドウ名です。
何も記述しないときはウィンドウ名に「名称未設定」が表示されます。
このように <head>〜</head>
は、その内容こそブラウザに表示されることはありませんが、ブラウザが
コンテンツを正しく表示するうえで必要な情報が記されています。
続いて <body>
に含まれるものを説明します。
<center>
は、</center>
までのものをブラウザの中央にセンタリング表示します。
<h1>〜</h1>
は「見出し」を表します。見出しは<h1>、<h2>、<h3>、・・・<h6>
という具合に全部で
6段階あり、タグの数字を大きくすると、次第に表示される見出しサイズは小さくなります。
(ブラウザによっては厳密に6段階で見出しを表現しないものもあります)
<pre>
は、タグにはさまれた文字列をそのまま、等幅フォントで表示します。
<table>〜</table>
は表組みを表し、<tr>
は表組み内のは行区切りを、<td>
は段区切りを表します。
HTMLでおそらく最も馴染みのある ハイパーリンク は<a href="〜">〜</a>
で記述します。
<a>
タグに挟まれた部分がリンク元で、そこをクリックすると href="〜"
で指定のURLへとリンクします。
<html> <head> <meta http-equiv="Content-Language" content="ja"> <meta http-equiv="Content-Type" content="text/html; charset=shift_jis"> <title> 商品マスターファイル </title> </head> <body> <center><h1> 商品マスターファイル </h1></center> <hr> <pre> <table cellpadding="1" cellspacing="0" border="0" bordercolor="#000000"> <tr> <td> 商品コード </td> <td> : </td> <td>SHCODE</td> </tr> <tr> <td> 商品名 </td> <td> : </td> <td>SHNAME</td> </tr> <tr> <td> 単価 </td> <td> : </td> <td>SHTANK</td> </tr> <tr> <td> 品種コード </td> <td> : </td> <td>SHSCOD</td> </tr> </table> </pre> <a href="/AS400-NET.USR/PROJECT/CGI003/DB2_DSPDSPHED.HTM"> 検索条件の入力に戻る</a> </body> </html>
入力された商品コードによって商品マスターを検索して、商品レコードを表示するRPG-CGI の全容を紹介します。
このCGIは商品マスターが見つからなかったときへの対応はありませんし、デコードについての記述もありませんが、それ以外はかなり実用的なサンプルとなっています。
0001.00 H DATEDIT(*YMD/) COPYRIGHT('(C) OfficeQuattro Co,.Ltd Japan 2001-') 0002.00 F******* 商品マスターの紹介 CGI サンプル *************************** 0003.00 FSHOHIN IF E K DISK USROPN 0004.00 F********************************************************************** 0005.00 D OVR S 80 DIM(2) CTDATA PERRCD(1) 0006.00 D HTML S 100 DIM(37) CTDATA PERRCD(1) 0007.00 D CD5026 S 1 DIM(26) CTDATA PERRCD(26) 0008.00 D CD5035 S 1 DIM(26) CTDATA PERRCD(26) 0009.00 *( フィールド名とフィールド値の保管配列 = 500 項目 ) 0010.00 D FDR S 20A DIM(500) 0011.00 D VLR S 256A DIM(500) 0012.00 D LNR S 4S 0 DIM(500) 0013.00 0014.00 *( プロシージャーのための作業変数の定義 ) 0015.00 D FIELD S 20A 0016.00 D VALUE DS 0017.00 D VAR 1 1024 0018.00 D DIM(1024) 0019.00 0020.00 *( API : QtmGetEnv のための変数の定義 ) 0021.00 D ENBUFF DS 0022.00 D EBR 1 2048 0023.00 D DIM(2048) 0024.00 D ENBUFLEN S 9B 0 INZ(2048) 0025.00 D ENACTLEN S 9B 0 INZ 0026.00 D ENVARNAM S 20A 0027.00 D ENVARLEN S 9B 0 0028.00 D LEN S 9P 0 0029.00 D RECBUF S 512A 0030.00 D OUTLEN S 9B 0 INZ(512) 0031.00 D CRLF C X'15' 0032.00 D REQMTH C CONST('REQUEST_METHOD') 0033.00 D QRYSTR C CONST('QUERY_STRING') 0034.00 D CONLEN C CONST('CONTENT_LENGTH') 0035.00 D HTMLSU C CONST(37) 0036.00 /COPY QSYSINC/QRPGLESRC,QUSEC 0037.00 C*----------------------------------------------------+ 0038.00 C* 環境変数 REQUEST_METHOD を取得して SUBMIT した 0039.00 C* メソッドが GET であるか POST であるかを調べる 0040.00 C*----------------------------------------------------+ 0041.00 C MOVEL REQMTH ENVARNAM 0042.00 C Z-ADD 14 ENVARLEN 0043.00 C EXSR GetEnv 0044.00 C MOVEL ENBUFF METHOD 4 0045.00 C MOVEL METHOD METH 3 0046.00 C METHOD CASEQ 'POST' Post 0047.00 C METH CASEQ 'GET' Get 0048.00 C ENDCS 0049.00 C*( 入力フィールド名とフィールド値を取得 ) 0050.00 C EXSR RtvField 0051.00 C* 0052.00 C MOVE *BLANKS FIELD 0053.00 C MOVEL 'SHCODE' FIELD 0054.00 C Z-ADD 1 N 4 0 0055.00 C FIELD LOOKUP FDR(N) 50 0056.00 C 50 MOVEL VLR(N) SHCODE 0057.00 C* 0058.00 C EXSR OPEN 0059.00 C SETOFF 99 0060.00 C SHCODE CHAIN SHOHIN 99 0061.00 C* 商品レコードが見つかれば HTML の個数の分を 0062.00 C* フィールド値を埋め込みながら出力する。 0063.00 C *IN99 IFEQ *OFF 0064.00 C 1 DO HTMLSU N 0065.00 C MOVEL HTML(N) RECBUF 0066.00 C EXSR SetField 0067.00 C CAT CRLF:0 RECBUF 0068.00 C ' ' CHECKR RECBUF OUTLEN 0069.00 C*----------------------------------------------------+ 0070.00 C CALLB 'QtmhWrStout' 99 0071.00 C PARM RECBUF 0072.00 C PARM OUTLEN 0073.00 C PARM QUSEC 0074.00 C*----------------------------------------------------+ 0075.00 C END 0076.00 C END 0077.00 C EXSR CLOSE 0078.00 C* 応答を良くするために LR 終了しない 0079.00 C RETURN 0080.00 C****************************************************** 0081.00 C *INZSR BEGSR 0082.00 C****************************************************** 0083.00 CSR EVAL ENBUFLEN = %SIZE(DBGPARM) 0084.00 C*( SETON LR が実行されることはありませんがコンパイルに LR が必要な 0085.00 C* ためのダミー処理です。この CGI は LR で終了しないので 0086.00 C* 2 回目以降のパフォーマンスが向上します。 ) 0087.00 CSR GOTO INZEND 0088.00 CSR SETON LR 0089.00 CSR INZEND ENDSR 0090.00 C****************************************************** 0091.00 C GetEnv BEGSR 0092.00 C****************************************************** 0093.00 C*( 環境変数値の取得 ) 0094.00 C*----------------------------------------------------+ 0095.00 C CALLB 'QtmhGetEnv' 99 0096.00 C PARM ENBUFF 0097.00 C PARM ENBUFLEN 0098.00 C PARM ENACTLEN 0099.00 C PARM ENVARNAM 0100.00 C PARM ENVARLEN 0101.00 C PARM QUSEC 0102.00 C*----------------------------------------------------+ 0103.00 CSR MOVE *BLANKS ENVARNAM 0104.00 CSR ENDSR 0105.00 C****************************************************** 0106.00 C Post BEGSR 0107.00 C****************************************************** 0108.00 C* POST の場合は環境変数 CONTENT_LENGTH を取得して 0109.00 C* その長さの分だけの標準入力を取得する 0110.00 CSR MOVEL CONLEN ENVARNAM 0111.00 CSR Z-ADD 14 ENVARLEN 0112.00 CSR EXSR GetEnv 0113.00 CSR EXSR atoi 0114.00 CSR Z-ADD LEN ENVARLEN 0115.00 CSR EXSR Stdin 0116.00 CSR ENDSR 0117.00 C****************************************************** 0118.00 C Get BEGSR 0119.00 C****************************************************** 0120.00 C* GET メソッドの場合は環境変数 QUERY_STRING に保管されている 0121.00 C* 入力値を取得する 0122.00 CSR MOVEL QRYSTR ENVARNAM 0123.00 CSR Z-ADD 12 ENVARLEN 0124.00 CSR Z-ADD 2048 ENBUFLEN 0125.00 CSR EXSR GetEnv 0126.00 CSR ENDSR 0127.00 C****************************************************** 0128.00 C atoi BEGSR 0129.00 C****************************************************** 0130.00 C* CONTENT_LENGTH として取得した文字列を数字に変換する 0131.00 CSR Z-ADD 0 LEN 0132.00 CSR 1 DO ENACTLEN N 4 0 0133.00 CSR MOVE EBR(N) DG01 1 0 0134.00 CSR MULT 10 LEN 0135.00 CSR ADD DG01 LEN 0136.00 CSR END 0137.00 CSR ENDSR 0138.00 C****************************************************** 0139.00 C Stdin BEGSR 0140.00 C****************************************************** 0141.00 C* POST メソッドの場合は標準入力の値を入力値として取得する 0142.00 C*----------------------------------------------------+ 0143.00 C CALLB 'QtmhRdStin' 99 0144.00 C PARM ENBUFF 0145.00 C PARM ENBUFLEN 0146.00 C PARM ENACTLEN 0147.00 C PARM QUSEC 0148.00 C*----------------------------------------------------+ 0149.00 CSR ENDSR 0150.00 C****************************************************** 0151.00 C RtvField BEGSR 0152.00 C****************************************************** 0153.00 C* 0154.00 C*--------------------------------------------------------------------+ 0155.00 C* GET の場合も POST の場合でも入力値は ENBUFF に戻されている 0156.00 C* 0157.00 C* ENBUFF にはフィールド値が 0158.00 C* FLD01=VAL01&FLD02=VAL02 ... FLD0N=VAL0N の形式で保管されている 0159.00 C* そこで 0160.00 C* 1. FLD01, FLD02,... FLD0N の値を切り取って取得する (PARSE) 0161.00 C* 2. 更にブラウザによってコード化されている VAL01, VAL02, ... の値を 0162.00 C* 元の文字列に戻す (DECODE) 0163.00 C*--------------------------------------------------------------------+ 0164.00 CSR Z-ADD 1 PS 4 0 0165.00 CSR Z-ADD 0 FD 4 0 0166.00 CSR ' ' CHECKR ENBUFF ENBUFLEN 0167.00 CSR DO *HIVAL 0168.00 CSR EVAL LEN = %SIZE(ENBUFF) 0169.00 CSR PS IFGT LEN 0170.00 CSR LEAVE 0171.00 CSR END 0172.00 CSR '=' SCAN ENBUFF:PS N 4 0 50 0173.00 CSRN50 LEAVE 0174.00 CSR N SUB PS LEN 0175.00 CSR MOVE *BLANKS FIELD 20 0176.00 CSR LEN SUBST ENBUFF:PS FIELD 0177.00 CSR N ADD 1 NXTPS 4 0 0178.00 C*( = VALUE の取り出し ) 0179.00 CSR Z-ADD 0 VL 4 0 0180.00 CSR MOVEA *BLANKS VAR 0181.00 CSR NXTPS DO ENBUFLEN N 4 0 0182.00 CSR N ADD 1 M 4 0 0183.00 CSR EBR(N) IFEQ '&' 0184.00 CSR EBR(N) OREQ '' 0185.00 CSR EBR(M) ANDEQ '0' 0186.00 CSR N OREQ ENBUFLEN 0187.00 C* 0188.00 CSR N IFEQ ENBUFLEN 0189.00 CSR ADD 1 VL 0190.00 CSR EVAL LEN = %SIZE(VALUE) 0191.00 CSR VL IFGT LEN 0192.00 CSR LEAVE 0193.00 CSR END 0194.00 CSR END 0195.00 C* 0196.00 CSR N ADD 1 NXTPS 0197.00 C* 0198.00 CSR LEAVE 0199.00 CSR ELSE 0200.00 CSR ADD 1 VL 0201.00 CSR EVAL LEN = %SIZE(VALUE) 0202.00 CSR VL IFGT LEN 0203.00 CSR LEAVE 0204.00 CSR END 0205.00 CSR MOVE EBR(N) VAR(VL) 0206.00 CSR END 0207.00 CSR END 0208.00 C*( VALUE をデコード ) 0209.00 C*--------------------------------------------------------------------+ 0210.00 C* ... 本当であれば、ここで漢字コードを組み立てて 0211.00 C* ASCII 漢字から EBCDIC 漢字への変換が必要 0212.00 C* %2F を / に変換も必要 0213.00 C* 長い処理になってしまうのでここでは省略 0214.00 C*--------------------------------------------------------------------+ 0215.00 C*( FIELD, VALUE を配列に保管しておく。 ) 0216.00 CSR ADD 1 FD 0217.00 CSR MOVEL FIELD FDR(FD) 0218.00 CSR MOVEL VALUE VLR(FD) 0219.00 CSR Z-ADD VL LNR(FD) 0220.00 CSR Z-ADD NXTPS PS 0221.00 CSR END 0222.00 C* 0223.00 CSR ENDSR 0224.00 C****************************************************** 0225.00 C SetField BEGSR 0226.00 C****************************************************** 0227.00 C* フィールド値を HTML の配列に埋め込む 0228.00 C*( SHCODE の値の埋め込み ) 0229.00 CSR 'SHCODE' SCAN RECBUF:1 M 4 0 50 0230.00 CSR *IN50 IFEQ *ON 0231.00 CSR MOVEA RECBUF VAR 0232.00 CSR MOVEA SHCODE VAR(M) 0233.00 CSR MOVEA VAR RECBUF 0234.00 CSR END 0235.00 C*( SHNAME の値の埋め込み ) 0236.00 CSR 'SHNAME' SCAN RECBUF:1 M 50 0237.00 CSR *IN50 IFEQ *ON 0238.00 CSR MOVEA RECBUF VAR 0239.00 CSR MOVEA SHNAME VAR(M) 0240.00 CSR MOVEA VAR RECBUF 0241.00 CSR END 0242.00 C*( SHTANK の値の埋め込み ) 0243.00 CSR 'SHTANK' SCAN RECBUF:1 M 50 0244.00 CSR *IN50 IFEQ *ON 0245.00 CSR MOVEA RECBUF VAR 0246.00 CSR MOVE SHTANK FLD7 7 0247.00 CSR MOVEA FLD7 VAR(M) 0248.00 CSR MOVEA VAR RECBUF 0249.00 CSR END 0250.00 C*( SHSCOD の値の埋め込み ) 0251.00 CSR 'SHSCOD' SCAN RECBUF:1 M 50 0252.00 CSR *IN50 IFEQ *ON 0253.00 CSR MOVEA RECBUF VAR 0254.00 CSR MOVEA ' ' VAR(M) 0255.00 CSR MOVEA SHSCOD VAR(M) 0256.00 CSR MOVEA VAR RECBUF 0257.00 CSR END 0258.00 C*( CCSID=5026 で稼動させるために英小文字を変換 ) 0259.00 CSR MOVEA RECBUF VAR 0260.00 CSR 1 DO 512 M 0261.00 CSR MOVE VAR(M) FLD1 1 0262.00 CSR FLD1 IFEQ X'0E' 0263.00 CSR SETON 51 0264.00 CSR END 0265.00 CSR *IN51 IFEQ *ON 0266.00 CSR FLD1 IFEQ X'0F' 0267.00 CSR SETOFF 51 0268.00 CSR END 0269.00 CSR ELSE 0270.00 CSR Z-ADD 1 K 4 0 0271.00 CSR FLD1 LOOKUP CD5026(K) 50 0272.00 CSR 50 MOVE CD5035(K) FLD1 0273.00 CSR 50 MOVE FLD1 VAR(M) 0274.00 CSR END 0275.00 CSR END 0276.00 CSR MOVEA VAR RECBUF 0277.00 CSR ENDSR 0278.00 C****************************************************** 0279.00 C OPEN BEGSR 0280.00 C****************************************************** 0281.00 C*( OVRDBF SHOHIN TOFILE(QTRFIL/SHOHIN) 0282.00 C*----------------------------------------------------+ OVRDBF 0283.00 C CALL 'QCMDEXC' 0284.00 C PARM OVR(1) 0285.00 C PARM 80 CMDLEN 15 5 0286.00 C*----------------------------------------------------+ 0287.00 CSRN99 OPEN SHOHIN 99 0288.00 CSRN99 SETON 81 0289.00 CSR ENDSR 0290.00 C****************************************************** 0291.00 C CLOSE BEGSR 0292.00 C****************************************************** 0293.00 C*----------------------------------------------------+ DLROVR 0294.00 C CALL 'QCMDEXC' 0295.00 C PARM OVR(2) 0296.00 C PARM 80 CMDLEN 15 5 0297.00 C*----------------------------------------------------+ 0298.00 CSR 81 CLOSE SHOHIN 99 0299.00 CSR ENDSR 0300.00 ** OVR 0301.00 OVRDBF FILE(SHOHIN) TOFILE(QTRFIL/SHOHIN) MBR(*FIRST) OVRSCOPE(*JOB) 0302.00 DLTOVR FILE(SHOHIN) LVL(*JOB) 0303.00 ** HTML 0304.00 <html> 0305.00 <head> 0306.00 <meta http-equiv="Content-Language" content="ja"> 0307.00 <meta http-equiv="Content-Type" content="text/html; charset=shift_jis"> 0308.00 0309.00 <title> 商品マスターファイル </title> 0310.00 </head> 0311.00 <body> 0312.00 <center><h1> 商品マスターファイル </h1></center> 0313.00 <hr> 0314.00 <pre> 0315.00 <table cellpadding="1" cellspacing="0" border="0" bordercolor="#000000" 0316.00 <tr> 0317.00 <td> 商品コード </td> 0318.00 <td> : </td> 0319.00 <td>SHCODE </td> 0320.00 </tr> 0321.00 <tr> 0322.00 <td> 商品名 </td> 0323.00 <td> : </td> 0324.00 <td>SHNAME </td> 0325.00 </tr> 0326.00 <tr> 0327.00 <td> 単価 </td> 0328.00 <td> : </td> 0329.00 <td>SHTANK </td> 0330.00 </tr> 0331.00 <tr> 0332.00 <td> 品種コード </td> 0333.00 <td> : </td> 0334.00 <td>SHSCOD</td> 0335.00 </tr> 0336.00 </table> 0337.00 </pre> SOSI <a href="/AS400-NET.USR/PROJECT/CGI003/DB2_DSPDSPHED.HTM"> 検索条件の 0339.00 </body> 0340.00 </html> 0341.00 ** CD5026 0342.00 abcdefghijklmnopqrstuvwxyz 0343.00 ** CD5035 0344.00 イウエオカキクケサシスセソタチツトハミヤユヨラリルレ
商品マスターに CHIAN してわずか37行のHTMLを出力するだけなのですが、これだけの結構、膨大な量のCGI となってしまいます。 CGI としての大きな流れは
コンパイルは
CRTRPGMOD MODULE(CGIBIN/CGI003) SRCFILE(PGMRLIB/QRPGLESRC) AUT(*ALL)
CRTPGM PGM(CGIBIN/CGI003) BNDSRVPGM(QTCP/QTMHCGI) AUT(*ALL)
のように行います。
(QTCP/QTMHCGI が見つからない場合は QHTTPSVR/QTMHCGI をバインドしてください。)
ざっと言えばこんな具合ですが、GET か POST かを判断してメソッドの種類によって入力値の取得方法が
異なってきますので、両方の取得の方法を紹介しています。
入力値を取得できた後でも入力値はブラウザから
FIELD1=VALUE1&FIELD2=VALUE2& .... FIELDN=VALUEN
の形式で送られてきますので、この文字列から
FIELD1, FIELD2, .... FIELDN
の値を切り取って取り出さなければなりません。 この作業のことを パース(PARSE) と呼びます。
パースを行っているのはサプ・ルーチン「RtvField」
ですが、かなり面倒な作業であることは
おわかりになるでしょう。
またブラウザはコードによる解釈の違いがないように、半角文字であってもコード化して送ってくるものもあります。
例えば文字「/」をブラウザは「%2F」として先頭に「%」をつけてコード化して送信してきます。
「%」の後に続く「2F」は ASCII のHEXコードです。
このような文字は他にもあります。半角カナもコード化されます。
CGI では「%2F」を「/」に戻さなければなりません。この作業のことを デコード(DECODE) と呼びます。
漢字の場合はもっと複雑です。漢字は2バイトに分割されて、ブラウザによってエンコードされて
送られてきますが、これを元のHEXコードに組み立てなおした(デコード)としても、それはASCIIの漢字です。
従って ASCII漢字に戻した後で更に APIなどによって CGI で EBCDICの漢字に変換してやる必要があります。
さらに厄介なことに ASCIIでは「梶vや「avなどのように 複数のコードを持つ漢字 もあり、EBCDICへのAPIによる変換は 片方しかサポートされていません。
「梶vや「avは機種依存の漢字と呼ばれており、どちらが入力されるのかは入力する操作員には判断することは
できません。
デコードには一般的な手法がありますが System i 独自のこのような難題が山積しているのは事実です。
簡単な例でもこのような問題が出てくるわけですから、複雑な機能を持つ CGI を開発するとなると
気の遠くなるような作業が待っていることが容易に想像することができます。
それらを何とか克服したとしても System i では EBCDICコードで出力しますので、
大量のHTMLを吐き出すとなると CGI では EBCDICからASCII への変換にオーバーヘッドを
大量に消費することになります。
また上記のような典型的な HTMLを CGIで吐き出す場合はHTMLを修正したい場合は CGI そのものを
修正する必要が出てきます。
CGIの開発者もHTMLに関する相当、深い知識も要求されてきます。
画像やスタイル・シートを使って複数のHTMLが必要になる場合のことを考えると CGIの開発者は
開発意欲が失せてしまうかも知れません。
気の遠くなるような作業に加えて IBMオリジナルHTTPサーバーのPOSTメソッドでは漢字のコードが
文字化けしてしまうという問題点もあります。
これは IBMオリジナルHTTPサーバーから CGIに送られてくる標準入力が 文字化け を起こしてしまう
という重大な欠陥です。
HTTPサーバーで文字化けを起こしているためにCGIでは、どのように工夫してもこれは避けることができない
問題です。