メニューボタン
IBMi海外記事2010.10.20

PHPを使ったRPGへのデータ構造の受け渡し

クリス・アンダーソン 著

PHPでXMLを分解してデータをRPGのデータ構造に渡すことが可

最近はDB2に情報を書き込む方法は山ほどあることにお気づきでしょう。ウェブ・サービスはそのための、頻繁に使用されている新しい方法の一つです。一般的にはウェブ・サービスは次のように動作します。大量のXMLデータがインターネット経由で送られ、データを解釈するメカニズムによって受け取られて、データが解釈されてプログラムに渡され処理されます。よくあることですが、こうしたタイプのサービスを作成するためのテクニックが多数利用可能で、ご想像の通りIBM iは他の環境に比べてより多くの方法を提供しています。RPGでもウェブ・サービスを構築することはできますが、PHPでウェブ・サービスを構築した方がずっと利便性が高いということがお分かりになるかもしれません。特に、既存のPHPベースのウェブ環境があってそこにあるデータをRPGに送って処理させる場合はなおさらです。

そのために、実際に動作するZend PHPウェブ・ページの(簡単ではありますが)例を構築します。これは、ポストされたXMLデータを受け取り(ただしアップロード経由で。ウェブ・サービスのフル機能を設計することは本稿の範囲を超えています)、そのデータを配列に分解しPRGプログラムに対してデータ構造として渡すことができます。この処理は、HTMLドキュメント(今回の場合、通常はウェブ・サービスのようなXMLデータを受け取る際のより高度な操作のための場所に過ぎませんが)、PHPドキュメント、RPGプログラム、DB2上の何らかのタイプの物理ファイルの4つの部分で構成されています。

HTML

このパズルの最初のピースは、アップロードされたファイルを受け取ってPHPプログラムに渡して以後の処理をしてもらうという基本的なHTMLフォームです。プロセスのこの部分については簡単にしておきます。この部分は単にデータをPHPプログラムに渡す基本的で容易な部分に過ぎないからです。この部分のHTMLページのコードを図―1に示します。

このページをブラウザで開くと、ファイルをアップロードするための[ブラウズ]ボタンと [送信]ボタンが表示されます。HTMLはこれだけです。繰り返しますが、PHPにデータを渡すための方法として実運用で使うことを意図したものではありません。その代わりに、単にこのHTMLフォームでこの処理のもっと興味深くそしてあまり文書化されていない部分がわかります。

DDSとRPG

この例のために、処理対象とするビジネス・データを表現する簡単なデータ・セットを使用します。基本的な顧客リストを表現するための物理ファイルを設定するのに使用するDDSを以下に示します。

*CUSTMAST.PF
A       R RCUSTMAST
A         ID           6    0
A         NAME        30
A         CITY        25
A         STATE        2
A         ZIP          9    0
A         BALANCE      6    2
A       K ID

HTMLと同様にRPG部分も手早く簡単にしますので、すでにご存じのことについては細かく触れません。図―2に示すプログラムはデータ構造をエントリ・パラメータとして受け取って、そのレコードを作成したばかりのデータファイルに書き出すという簡単なプログラムです。

PHP

コードを見ていく前に、PHP側からの処理の基本的なワークフローを見てみましょう。この処理は大きく3つのステップで構成されています。1番目はHTMLフォームからアップロードされたファイルを処理するステップです。2番目はネイティブのPHPのXML処理サポート機能を使用してXMLからデータを抽出しオブジェクト配列に格納します。この配列については後述しますが、RPGにデータを渡すには便利なフォーマットです。最後に、Zend i5ツールキットを使用してシステムへの接続をオープンしRPGプログラムの呼び出しの定義と準備をします。

まずPHPタグをオープンして、アップロードされたファイルを一時的な場所から永続的な場所へ移動します。

<?php
$file = $_FILES["file"];
$filename = basename ($file["name"]);
$target = $filename;
move_uploaded_file ($file["tmp_name"], $target)
  or die("Error uploading file.");

この処理についてあまりご存じでない方のために、この処理は基本的には、HTMLフォームから渡されたデータに対してファイルの名前とそのファイルが今一時的にどこに格納されているのかを問い合わせていると理解ください。次に、このファイルをその一時保管場所から処理可能な場所へコピーします。今回の例の場合、このファイルはスクリプトが保管されている場所と同じディレクトリに保管されています。

次に、XMLを構文解析して簡単なPHPオブジェクトに格納します。PHPのネイティブXMLサポートのおかげで、次の一行でこれができてしまいます。

$xml = simplexml_load_file($target);

このコード文はXMLから簡単なオブジェクトを作成し、XMLドキュメントの構造を反映させた階層的な方法でデータにアクセスできるようにしてくれます。PHPはXMLを想定して設計されていますので、PHPでXMLを処理する方法は多数ありますが、その名前から想像できる通りこの方法が最も簡単です。もちろん送信するドキュメントが必要で、それは以下のコードで作成します。

<customers>
  <customer>
   <id>10000</id>
   <name>ACME Things and Stuff, Inc.</name>
   <city>Yourtown</city>
   <state>WI</state>
   <zip>543423342</zip>
   <balance>100.00</balance>
  </customer>
  <customer>
   <id>100392</id>
   <name>Watershed Ditches</name>
   <city>Rainy</city>
   <state>WA</state>
   <zip>938283332</zip>
   <balance>473.11</balance>
  </customer>
  <customer>
   <id>100923</id>
   <name>Winning Team Trophy</name>
   <city>Windy City</city>
   <state>IL</state>
   <zip>601023432</zip>
   <balance>392.20</balance>
  </customer>
</customers>

ご覧になってお分かりの通り、ファイルには3件の顧客レコードがあり、前述のDDSとRPGソースで定義したものと全く同じフィールドが含まれています。PHPがXMLを変換した後は、図―3に示すような基本的な構造をしたオブジェクトができます。したがって2件目の顧客の所在都市についての情報にアクセスしたい場合は、次のようなコード片を使用します。

$secondCity = $xml->customer[1]->city;

XMLの構造を最適化してPHP側の処理を簡単にする方法はたくさんありますが、基本的な変換テクニックはここで示した簡単な例で説明されています。もちろんPHPの配列にデータを格納するのも良いですが、その場合RPGプログラムにはどのように渡すのでしょうか。まず、図―4に示すようにIBM iへの接続をオープンする必要があります。ユーザー名、パスワード、初期ライブラリ・リストに自分の場合の値を指定し、ツールキットを使用してi5へ接続します。

次のステップはプログラムを呼び出すための準備です。RPGへ渡すパラメータの構造を渡すところから始めます。今回の例の場合、1件の顧客情報を含むデータ構造を使用します(図―5)。

さてこれでたくさんの配列ができることになりますが、この配列を3つのレベルに分解することが可能です。1つ目がすべてのパラメータの配列です。データ構造に沿っていない情報を渡す場合、2番目のレベルはバイパスして各パラメータの名前、使用方法、データ・タイプ、データ長を記述した配列のリストを渡すだけでよいです。今回の例ではデータ構造を使用していますので、パラメータ自体がサブパラメータの配列となっており、そのサブパラメータが3番目のレベルになっています。一般的にこういうデータを大量に処理したい場合は、この処理を要約してコードの記述量を削減し、エラーが混入する確率を低くすることをお勧めします。

さてこれですべての値を文字列としてデータ構造に渡せたことになります。こうしたのはRPGが実行時にデータ構造を文字列の塊として受け取って、構文解析して各変数へ格納するからです。浮動小数点タイプや整数タイプのデータを渡そうとすると予想外の結果になることがあります。もちろん整数タイプや浮動小数点タイプの値は、RPG用にサイズを調整する必要があります。これについては後述します。この記述が完了したら図―6に示すコードを使用してプログラムを呼び出す準備をします。

i5_program_prepareコマンドは前に準備したプログラム(ライブラリ/オブジェクト)の名前と中身を受け取ります。この時点でこのコマンドはIBM iと通信し、すべてが適切に構成されていることとプログラムが実際に存在して実行可能な状態になっていることを確認します。

次にパラメータを作成してプログラムを呼び出さなければなりません。XMLオブジェクト中の各顧客レコードに対しプログラムの呼び出しを繰り返します。実運用環境では、パフォーマンス上の観点からプログラムを複数回呼び出すのではなく、データ構造の配列を使用してプログラムを一度呼び出す方が望ましいでしょう。しかし実際に何が起こっているのかを理解しやすくするために、このプログラム例では複数回呼び出しています。

図―7のコード部分は各顧客に対して繰り返し処理を行い、XMLの値をパラメータ配列に移動させてパラメータを作成している箇所で、これは前述の通りに定義した記述に基づいています。配列の各要素は記述から「name」の値をキーとして、XML値を値として持っています。ここで、simpleXMLオブジェクトを処理する際に、このオブジェクトの各要素自体もsimpleXMLオブジェクトであるという点を意識することが重要です。このため、このオブジェクトをパラメータ用に文字列に変換しているところがあるのがお分かりになるでしょう。また、小数値「balance」については、6バイト長であり小数点が正しい位置にあることを確認するための追加の処理を行います。

関数i5_program_callは、準備されたプログラム、呼び出し側パラメータが入っている変数、RPGプログラムから返された値を格納する変数、の3つのパラメータを受け取ります。今回の例の場合は、RPGプログラムに渡した値は変更されませんので同じ変数を使用します。関数i5_program_callは変数$resultにtrueまたはfalseの値を格納し、呼び出しが正常に完了したかを示します。

残っている処理はプログラム・オブジェクトをクローズしてiへの接続をクローズすることだけです。i5の接続はスクリプトが終了した時に自動的にクローズされますが、スタイル上あるいは本稿の範囲を超えた様々な実際的な理由から、模範例として次のコード片を入れておくことをお勧めします。

i5_program_close($pgm);
i5_close($i5);

以上で終了です。もちろんこのインタフェースを使用して、データの完全性やエラー・チェックなどのより多くの補強を行うこともできます。しかしこのしっかりした基礎があれば、XMLとi5_toolkitを使用してRPGにデータ構造を渡すことができます。

あわせて読みたい記事

PAGE TOP