さて、前述の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では、どのように工夫してもこれは避けることができない
問題です。