以下のような簡単なExcelシートをAPEXアプリケーションにアップロードし、その内容でフォームの穴埋めをします。
クラシック・レポートを使ってブラウザで穴埋めする実装と、APEXコレクションを使ってサーバー側で穴埋めする実装の2種類を試してみます。
アプリケーション作成ウィザードを起動し、空のアプリケーションを作成します。名前はExcel Formとします。
クラシック・レポートを使う
空白ページを作成します。ページ定義の名前はClassic Reportとします。
フォームの穴埋めに使うExcelファイルを指定するページ・アイテムを作成します。
識別の名前はP2_FILE、タイプはファイル参照...を選びます。設定の記憶域のタイプとしてTable APEX_APPLICATION_TEMP_FILES、ファイルをパージするタイミングとしてEnd of Sessionを選びます。表示形式は任意ですが、ここではInline File Browseを選択しています。
セッション・ステートのストレージはセッションごと(永続)を選択します。
ファイルをアップロードするボタンを作成します。
識別のボタン名はSUBMIT、ラベルはSubmitとします。動作のアクションはページの送信です。
Excelシートから取り出した値を保持するページ・アイテムを作成します。
ページ・アイテムP2_NAMEに氏名、P2_DEPTに所属、P2_PURPOSEに目的、P2_AMOUNTに金額を保持します。P2_NAME、P2_DEPT、P2_PURPOSEのタイプはテキスト・フィールド、P2_AMOUNTは数値フィールドとします。
セッション・ステートのストレージはリクエストごと(メモリーのみ)とします。
クラシック・レポートのリージョンを作成し、アップロードされたExcelを表形式にします。
リージョンを作成し、識別のタイトルとしてDocument、タイプとしてクラシック・レポートを選択します。ソースのタイプとしてSQL問合せを選択し、SQL問合せとして以下を記述します。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
select col001, col002 | |
from apex_data_parser.parse( | |
p_content => ( | |
select blob_content from apex_application_temp_files where name = :P2_FILE | |
), | |
p_file_name => 'dummy.xlsx' | |
) |
詳細の静的IDとしてdocumentを設定します。
属性の遅延ロードはオフにします。
ページ・プロパティのJavaScriptのページ・ロード時に実行に、以下を記述します。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// レポートを非表示にする | |
document.getElementById("document").style.display = "none"; | |
let doc = document.getElementById("report_table_document").tBodies[0]; | |
for (let i = 0; i < doc.rows.length; i++) { | |
let label = doc.rows[i].cells[0].textContent; | |
let value = doc.rows[i].cells[1].textContent; | |
switch(label) { | |
case "氏名": | |
apex.items.P2_NAME.setValue(value); | |
break; | |
case "所属": | |
apex.items.P2_DEPT.setValue(value); | |
break; | |
case "目的": | |
apex.items.P2_PURPOSE.setValue(value); | |
break; | |
case "金額": | |
apex.items.P2_AMOUNT.setValue(value); | |
break; | |
}; | |
} |
ページの表示時に一瞬レポートが表示されます。それを抑止するために、ページのテンプレート・オプションを開き、Deferred Page Renderingにチェックを入れます。
遅延ロードをオンにする
クラシック・レポートの遅延ロードがオンの場合は、クラシック・レポートの表示はページのロードとは非同期で実行されます。そのため、JavaScriptによる穴埋め処理は動的アクションのイベントリフレッシュ後に実行する必要があります。
ページ番号2のコピーをページ番号3として作成し、クラシック・レポートの遅延ロードをオンにします。
クラシック・レポートに動的アクションを作成します。
タイミングのイベントとしてリフレッシュ後を選択します。
TRUEアクションとしてJavaScriptコードの実行を選択し、設定のコードとして以下を記述します。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// レポートを非表示にする | |
document.getElementById("document").style.display = "none"; | |
let doc = document.getElementById("report_table_document").tBodies[0]; | |
for (let i = 0; i < doc.rows.length; i++) { | |
let label = doc.rows[i].cells[0].textContent; | |
let value = doc.rows[i].cells[1].textContent; | |
switch(label) { | |
case "氏名": | |
apex.items.P3_NAME.setValue(value); | |
break; | |
case "所属": | |
apex.items.P3_DEPT.setValue(value); | |
break; | |
case "目的": | |
apex.items.P3_PURPOSE.setValue(value); | |
break; | |
case "金額": | |
apex.items.P3_AMOUNT.setValue(value); | |
break; | |
}; | |
} |
ページ・プロパティのJavaScriptのページ・ロード時に実行に記載されたコードは削除します。
以上で実装は完了です。
遅延ロードをオンにしている場合、レポートのリフレッシュ後に一瞬レポートが表示される状況を抑止するのは難しそうです。
APEXコレクションを使う
ページ番号3のコピーをページ番号4として作成し、クラシック・レポートのリージョンを削除します。
アップロードされたExcelからAPEXコレクションを作成し、それからフォームの穴埋めを行います。
プロセス・ビューを表示させ、新規にプロセスを作成します。
識別の名前はFill Form、タイプとしてコードを実行を選択します。ソースのPL/SQLコードに以下を記述します。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
declare | |
l_sql varchar2(2000); | |
begin | |
-- APEXコレクションのソースとなるSELECT文 | |
l_sql := q'~select col001, col002 | |
from apex_data_parser.parse( | |
p_content => ( | |
select blob_content from apex_application_temp_files where name = '&P4_FILE.' | |
), | |
p_file_name => 'dummy.xlsx' | |
)~'; | |
l_sql := replace(l_sql, '&P4_FILE.',:P4_FILE); | |
-- APEXコレクションを作る | |
apex_collection.create_collection_from_query( | |
p_collection_name => 'DOCUMENT' | |
,p_query => l_sql | |
,p_truncate_if_exists => 'YES' | |
); | |
-- フォームの穴埋め | |
select c002 into :P4_NAME from apex_collections where collection_name = 'DOCUMENT' and c001 = '氏名'; | |
select c002 into :P4_DEPT from apex_collections where collection_name = 'DOCUMENT' and c001 = '所属'; | |
select c002 into :P4_PURPOSE from apex_collections where collection_name = 'DOCUMENT' and c001 = '目的'; | |
select c002 into :P4_AMOUNT from apex_collections where collection_name = 'DOCUMENT' and c001 = '金額'; | |
end; |
サーバー側の条件のボタン押下時にSUBMITを指定します。
サーバー側で実行されるプロセスでページ・アイテムに値を設定しているため、穴埋めに使用されるページ・アイテムのセッション・ステートのストレージはセッションごと(永続)にする必要があります。
反対に、アップロードするファイルを参照するページ・アイテムの設定のファイルをパージするタイミングはEnd of Request、セッション・ステートのストレージはリクエストごと(メモリーのみ)に変更できます。
以上で実装は完了です。
クラシック・レポートを使った実装を紹介していますが、APEXコレクションを使った実装が一番扱いやすいと思います。
今回作成したAPEXアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/fill-form-excel.zip
Oracle APEXのアプリケーション作成の参考になれば幸いです。
完