変換タグ
4Dでは、参照を 4D変数や式に挿入したり、様々な処理をソーステキスト ("テンプレート") に対して実行したりするための変換タグのセットを用意しています。 これらのタグは、ソーステキストが実行されてアウトプットテキストが生成されたときに解釈されます。
4D Webサーバーにおいて Web テンプレートページ をビルドするにあたって、この原理が使用されます。
これらのタグは原則として HTMLコメント (<!--#Tag Contents-->
) として挿入します。 しかしながら、xml に準じた代替シンタックス も一部利用可能です。
複数タイプのタグを混用することも可能です。 たとえば、以下の HTML構造は、問題なく実行可能です:
<HTML>
<BODY>
<!--#4DSCRIPT/PRE_PROCESS--> (メソッド呼び出し)
<!--#4DIF (myvar=1)--> (If 条件)
<!--#4DINCLUDE banner1.html--> (サブページ挿入)
<!--#4DENDIF--> (End if)
<!--#4DIF (mtvar=2)-->
<!--#4DINCLUDE banner2.html-->
<!--#4DENDIF-->
<!--#4DLOOP [TABLE]--> (カレントセレクションでのループ)
<!--#4DIF ([TABLE]ValNum>10)--> (If [TABLE]ValNum>10)
<!--#4DINCLUDE subpage.html--> (サブページの挿入)
<!--#4DELSE--> (Else)
<B>Value: <!--#4DTEXT [TABLE]ValNum--></B><br/> (フィールド表示)
<!--#4DENDIF-->
<!--#4DENDLOOP--> ](End for)
</BODY>
</HTML>
タグ利用の原則
解析
テンプレート ソースの解析は、2つのコンテキストでおこなわれます:
-
PROCESS 4D TAGS
コマンド使用時: このコマンドは テンプレート に加えて任意の引数を受け入れ、処理の結果であるテキストを返します。 -
4D の統合された HTTPサーバー使用時:
WEB SEND FILE
(.htm, .html, .shtm, .shtml)、WEB SEND BLOB
(text/html型 BLOB)、およびWEB SEND TEXT
コマンドによって テンプレートページ を送信、あるいは URL で呼び出します。 URL で呼び出す場合、".htm" と ".html" で終わるページは最適化のため解析されません。 この場合に HTMLページを解析するには、末尾を ".shtm" または ".shtml" とする必要があります (例: http://www.server.com/dir/page.shtm)。
再起的処理
4Dタグは繰り返し解釈されます。4D は常に変換の結果を解釈しようとし、新しい変換が起きた際にはそれに伴う新しい解釈が実行され、取得結果の変換が必要がなくなるまで繰り返されます。 たとえば、以下のようなステートメントがあった場合:
<!--#4DHTML [Mail]Letter_type-->
もし [Mail]Letter_type
テキストフィールド自体にもタグ (たとえば <!--#4DSCRIPT/m_Gender-->
) が含まれていた場合、このタグは 4DHTMLタグの解釈の後に、それに伴って評価されます。
この強力な原則は、テキスト変換に関連するほとんどの需要を満たすことができます。 しかしながら、Webコンテキストにおいて、これは場合によって悪意のあるコードの侵入を許す可能性があるという点に注意が必要です。これを防ぐ方法については 悪意あるコードの侵入を防止 を参照ください。
トークンを使用した識別子
4D のバージョ ンや言語設定に左右されずに、タグ経由の式の評価が正しくおこなわれることを確実にするため、バージョン間で名前が変わりうる要素 (コマンド、テーブル、フィールド、定数) については、トークンシンタックスを使用することが推奨されます。 たとえば、Current time
コマンドを挿入するには、"Current time:C178
"と入力します。
"." を小数点として使用
4D は常にピリオド文字 (.) を小数点として使用して、 4DTEXT、4DHTML、および 4DEVAL の 4Dタグで数値表現を評価します。 リージョン設定は無視されます。 この機能により、4Dの言語設定とバージョンが異なっていてもメンテナンスが容易となり互換性が保たれます。
4DBASE
シンタックス: <!--#4DBASE folderPath-->
<!--#4DBASE -->
タグは <!--#4DINCLUDE-->
タグで使用されるワーキングディレクトリを指定します。
Webページ内で呼び出されると、<!--#4DBASE -->
タグは同ページ内であとに続くすべての <!--#4DINCLUDE-->
呼び出しのディレクトリを変更します (次の <!--#4DBASE -->
があるまで)。 組み込まれたファイル内で <!--#4DBASE -->
フォルダーが変更されると、親のファイルから元となる値を取得します。
folderPath 引数には現在のページに対する相対パスを指定し、パスは "/
" で終わっていなければなりません。 また、指定フォルダーは Webフォルダー内になければなりません。
"WEBFOLDER" キーワードを渡すと、(そのページに対して相対の) デフォルトパスに戻されます。
以下のように、各呼び出しごとに相対パスを指定したコードは:
<!--#4DINCLUDE subpage.html-->
<!--#4DINCLUDE folder/subpage1.html-->
<!--#4DINCLUDE folder/subpage2.html-->
<!--#4DINCLUDE folder/subpage3.html-->
<!--#4DINCLUDE ../folder/subpage.html-->
... これは次と同等です。
<!--#4DINCLUDE subpage.html-->
<!--#4DBASE folder/-->
<!--#4DINCLUDE subpage1.html-->
<!--#4DINCLUDE subpage2.html-->
<!--#4DINCLUDE subpage3.html-->
<!--#4DBASE ../folder/-->
<!--#4DINCLUDE subpage.html-->
<!--#4DBASE WEBFOLDER-->
たとえば、ホームページのディレクトリを設定する場合:
/* Index.html */
<!--#4DIF LangFR=True-->
<!--#4DBASE FR/-->
<!--#4DELSE-->
<!--#4DBASE US/-->
<!--#4DENDIF-->
<!--#4DINCLUDE head.html-->
<!--#4DINCLUDE body.html-->
<!--#4DINCLUDE footer.html-->
上で組み込まれる "head.html" ファイル内でカレントフォルダーが <!--#4DBASE -->
を使用して変更されても、"index.html" 内では変更されません:
/* Head.htm */
/* ここでのワーキングディレクトリはインクルードされるファイルに対して相対的 (FR/ または US/) */
<!--#4DBASE Styles/-->
<!--#4DINCLUDE main.css-->
<!--#4DINCLUDE product.css-->
<!--#4DBASE Scripts/-->
<!--#4DINCLUDE main.js-->
<!--#4DINCLUDE product.js-->
4DCODE
シンタックス: <!--#4DCODE codeLines-->
4DCODE
タグを使用すると、複数行の4Dコードのブロックをテンプレートに挿入できます。
<!--#4DCODE
シークエンスとそれに続くスペース、CR または LF 文字が検知されると、4D は次の -->
シークエンスまでのコードを解釈します。 コードブロック自体はキャリッジリターンもラインフィードも、あるいはその両方も含むことができ、4D によってシーケンシャルに解釈されます。
たとえば、以下のようにテンプレートに書くことができます:
<!--#4DCODE
// パラメーターの初期化
C_OBJECT:C1216($graphParameters)
OB SET:C1220($graphParameters;"graphType";1)
$graphType:=1
// ...ここにコードを書きます
If(OB Is defined:C1231($graphParameters;"graphType"))
$graphType:=OB GET:C1224($graphParameters;"graphType")
If($graphType=7)
$nbSeries:=1
If($nbValues>8)
DELETE FROM ARRAY:C228 ($yValuesArrPtr{1}->;9;100000)
$nbValues:=8
End if
End if
End if
-->
4DCODE タグの機能は以下の通りです:
TRACE
コマンドがサポートされています。これは 4Dデバッガーを起動するので、テンプレートコードをデバッグすることができます。- エラーは標準のエラーダイアログを表示します。これを使って、ユーザーはコードの実行を中止したりデバッグモードに入ったりすることができます。
<!--#4DCODE
と-->
の間のテキストは改行され、どのような改行コードでも受け取ります (cr、lf、または crlf)。- テキストは
PROCESS 4D TAGS
を呼び出したデータベースのコンテキストにてトークナイズされます。 これは、たとえばプロジェクトメソッドの認識等において重要です。 公開オプション: 4DタグとURL(4DACTION...) メソッドプロパティは考慮されません。 - テキストが常に English-US設定であったとしても、4Dのバージョン間においてコマンドや定数名が改名されることによる問題を避けるため、コマンド名や定数名はトークンシンタックスを使用することが推奨されいます。
4DCODE タグがあらゆる 4Dランゲージコマンドおよびプロジェクトメソッドを呼び出せるという事実は、とくにデータベースが HTTP経由で使用可能な場合等に、セキュリティ上の問題になり得ます。 しかしながら、タグはサーバー側のコードをテンプレートファイルから実行するため、タグそのものはセキュリティ上の問題になりません。 このような コンテキストにおいては、あらゆる Webサーバーと同様に、セキュリティは主にサーバーファイルへのリモートアクセスレベルにおいて管理されています。
4DEACH と 4DENDEACH
シンタックス: <!--#4DEACH variable in expression-->
<!--#4DENDEACH-->
<!--#4DEACH-->
コメントは、expression に含まれるすべての要素に対して処理を繰り返します。 各要素は variable に代入され、その型は expression の型に依存します。
<!--#4DEACH-->
コメントは 3種類の expression を対象に反復処理をおこなうことができます:
- コレクション: コレクションの各要素をループします
- エンティティセレクション: エンティティセレクションの各エンティティをループします
- オブジェクト: オブジェクトの各プロパティをループします
ループの数は開始時に評価され、処理中に変化することは ありません。 ループ中に項目を追加・削除することは、繰り返しの不足・重複を引き起こすことがあるため、一般的には推奨されません。
<!--#4DEACH item in collection-->
このシンタックスは、コレクション の 各要素 を対象に反復処理をおこないます。 <!--#4DEACH -->
と <!--#4DENDEACH-->
の間に書かれたコードが、各コレクション要素について繰り返されます。
item はコレクション要素と同じ型の変数です。
コレクションの 要素はすべて同じ型 でなくてはなりません。そうでない場合には、item 変数に別の型の値が代入されたときにエラーが生成されます。
ループの回数はコレクションの要素数に基づいています。 各繰り返しにおいて、item 変数には、コレクションの合致する要素が自動的に代入されます。 このとき、以下の点に注意する必要があります:
- item 変数がオブジェクト型あるいはコレクション型であった場合 (つまり expression がオブジェクトのコレクション、あるいはコレクションのコレクションであった場合)、この変数を変更すると自動的にコレクションの対応する要素も変更されます (オブジェクトとコレクションは同じ参照を共有しているからです)。 変数がスカラー型である場合には、変数のみが変更されます。
- item 変数には、コレクションの先頭要素 の型が設定されます。 コレクション要素のどれか一つでも、変数と異なる型のものがあった場合、エラーが生成され、ループは停止します。
- コレクションが Null値の要素を格納していたとき、item 変数の型が Null値をサポートしない型 (倍長整数変数など) であった場合にはエラーが生成されます。
例題: スカラー値のコレクション
getNames は文字列のコレクションを返すメソッドです。 このメソッドは 公開オプション: 4DタグとURL が有効になっています。
<table class="table">
<tr><th>Name</th></tr>
<!--#4DEACH $name in getNames-->
<tr>
<td><!--#4DTEXT $name--></td>
</tr>
<!--#4DENDEACH-->
</table>
例題: オブジェクトのコレクション
getSalesPersons はオブジェクトのコレクションを返すメソッドです。
<table class="table">
<!--#4DCODE
$salePersons:=getSalesPersons
-->
<tr><th>ID</th><th>Firstname</th><th>Lastname</th></tr>
<!--#4DEACH $salesPerson in $salePersons-->
<tr>
<td><!--#4DTEXT $salesPerson.ID--></td>
<td><!--#4DTEXT $salesPerson.firstname--></td>
<td><!--#4DTEXT $salesPerson.lastname--></td>
</tr>
<!--#4DENDEACH-->
</table>
<!--#4DEACH entity in entitySelection-->
このシンタックスは、エンティティセレクション の 各エンティティ を対象に反復処理をおこないます。 <!--#4DEACH -->
と <!--#4DENDEACH-->
の間に書かれたコードが、エンティティセレクションの各エンティティについて繰り返されます。
entity は Entityクラスのオブジェクト変数です。
ループの回数はエンティティセレクション内のエンティティの数に基づきます。 各繰り返しにおいて、entity オブジェクト変数には、エンティティセレクションの合致するエンティティが自動的に代入されます。
例題: html のテーブル
<table class="table">
<tr><th>ID</th><th>Name</th><th>Total purchase</th></tr>
<!--#4DEACH $customer in ds.Customers.all()-->
<tr>
<td><!--#4DTEXT $customer.ID--></td>
<td><!--#4DTEXT $customer.name--></td>
<td><center><!--#4DTEXT String($customer.totalPurchase;"$###,##0")--></center></td>
</tr>
<!--#4DENDEACH-->
</table>
例題: PROCESS 4D TAGS
var customers : cs.CustomersSelection
var $input; $output : Text
customers:=ds.Customers.all()
$input:="<!--#4DEACH $cust in customers-->"
$input:=$input+"<!--#4DTEXT $cust.name -->"+Char(Carriage return)
$input:=$input+"<!--#4DENDEACH-->"
PROCESS 4D TAGS($input; $output)
TEXT TO DOCUMENT("customers.txt"; $output)
<!--#4DEACH property in object-->
このシンタックスは、オブジェクト の 各プロパティ を対象に反復処理をおこないます。 <!--#4DEACH -->
と <!--#4DENDEACH-->
の間に書かれたコードが、各オブジェクトプロパティについて繰り返されます。
property は現在処理中のプロパティ名が自動代入されたテキスト変数です。
オブジェクトのプロパティは作成順に処理されていきます。 ループ中、プロパティをオブジェクトに追加/削除することが可能ですが、その場合でも残りのループ回数は、オブジェクトの元のプロパティ数に基づいているため、変化しません。