最初から全ての法令データをロードしようとすると時間がかかるので、憲法のデータを使ってアプリケーションを作成します。アプリケーションが完成したら全ての法令データをデータベースにロードしてみます。
法令分類データの憲法をダウンロードします。1_xml.zipがダウンロードされます。
ダウンロードした1_xml.zipには、法令の一覧が記載されている1.csvというCSVファイルと、法令本文であるXMLファイルがそれぞれ個別のディレクトリの下に含まれています。
ディレクトリ名と法令本文のファイル名は同じで、XMLファイルには.xmlの拡張子が付けられています。例えば法令番号昭和二十一年憲法にあたるファイルは以下です。
321CONSTITUTION_19470503_000000000000000/321CONSTITUTION_19470503_000000000000000.xml
CSVに記載されている一覧の情報と法令本文であるXMLファイルを、以下の表JLAW_DATAに保存します。列BODYとBODY_HASHはXMLファイルの情報なので、CSVファイルには含まれません。列IDは列BODY_URL(CSVでは本文URL)の一部を取り出して割り当てます。
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
create table jlaw_data ( | |
id varchar2(40 char) not null | |
constraint jlaw_data_id_pk primary key, | |
law_type varchar2(16 char), -- 法令種別 | |
law_number varchar2(100 char), -- 法令番号 | |
law_title varchar2(400 char), -- 法令名 | |
law_title_kana varchar2(400 char), -- 法令名読み | |
law_title_former varchar2(600 char), -- 旧法令名 | |
promulgation_date varchar2(16 char), -- 公布日 | |
law_title_ammended varchar2(400 char), -- 改正法令名 | |
law_number_ammended varchar2(100 char), -- 改正法令番号 | |
promulgation_date_ammended varchar2(16 char), -- 改正法令公布日 | |
enforcement_date varchar2(16 char), -- 施行日 | |
enforcement_date_remark varchar2(200 char), -- 施行日備考 | |
law_id varchar2(16 char), -- 法令ID | |
body_url varchar2(100 char), -- 本文URL | |
not_in_force varchar2(1 char), -- 未施行 | |
body xmltype, -- 本文 | |
body_hash raw(32) -- 本文ハッシュ(SHA-256) | |
) | |
xmltype body store as binary xml | |
; |
上記の表を作成した後、この表に法令データをロードするAPEXアプリケーションを作成します。
アプリケーション作成ウィザードを起動します。作成するアプリケーションの名前はe-Gov法令とします。デフォルトで追加されているホーム・ページを削除し、代わりに表JLAW_DATAをソースとした対話モード・レポートのページを追加します。
以上でアプリケーションの作成を実行します。
アプリケーションが作成されたら、最初にデータ・ロード定義を作成します。
共有コンポーネントのデータ・ロード定義を開きます。
データ・ロードの作成は最初から行います。
次へ進みます。
次へ進みます。
ソース・タイプはファイルのアップロードとし、サンプル・ファイルとしてダウンロードした法令データに含まれる1.csvを選択します。
次へ進みます。
列見出しの最初の行にヘッダーが含まれるにチェックを入れます。列のマッピングについては、表JLAW_DATAのDDLのコメントにマップ先とソース列の対応が記載されています。
主キー列は後で本文URLからSQL式を用いて生成します。そのため、ここでは主キーにチェックを入れる列はありません。
データ・ロードの作成をクリックします。
データ・ロード定義としてLOAD_CSVが作成されます。これを編集します。
静的IDは大文字および小文字のどちらでもよいのですが、大文字のLOAD_CSVに変更します。ケース・センシティブなので、大文字小文字で異なっていると、別の定義と見做されます。設定のロード・メソッドはマージを選択します。
データ・プロファイルの編集を開きます。
列タイプにSQL式を選択します。名前はIDです。データ型はVARCHAR2、長さは40とします。設定の主キーはオンにします。
ソースのSQL式として以下を記述します。本文URLの引数にlawidとして指定されている値を主キー列IDに設定します。
旧
replace(BODY_URL, 'https://elaws.e-gov.go.jp/document?lawid=')
e-Gov法令検索リニューアル後
replace(replace(BODY_URL, 'https://laws.e-gov.go.jp/law/'),'/','_')
replace(replace(BODY_URL, 'https://laws.e-gov.go.jp/law/'),'/','_')
作成をクリックします。
データ・プロファイルに列IDが追加されました。
変更の適用をクリックします。
以上でデータ・ロード定義LOAD_CSVは完成です。
変更の適用をクリックします。
CSVファイルをロードするページを作成します。
ページ作成ウィザードを開きます。
データのロードを選択します。
ページの名前はCSVのロードとします。データ・ロード属性のデータ・ロードに先ほど作成したLOAD_CSVを選択します。データのアップロード元はファイル、最大ファイル・サイズ(MB)に10を入力します。すべての法令データに含まれるCSVファイルのサイズはほぼ6MBなので、それをロードできるサイズにしています。
ナビゲーションはデフォルトから変更せず、ブレッドクラムとナビゲーションの双方を作成します。
ページの作成をクリックします。
ファイルの選択をクリックし、1.csvを選択します。
ホーム・ページの対話モード・レポートにも、ロードされたデータが一覧されます。
XMLファイルをロードする機能を追加します。
ページ・デザイナでホーム・ページを開きます。
その都度、e-Gov法令のページから法令データをダウンロードするのは手間なので、URLを入力して、ZIPファイルのダウンロードからデータのロードまで一気に行うようにします。
URLを入力するページ・アイテムとしてP1_URLを作成します。識別のタイプはテキスト・フィールド、ラベルはURL、設定のサブタイプとしてURLを選択します。
ラベルはLoad、外観のホットをオンにします。テンプレート・オプションを開き、WidthをStretchに変更します。
動作のアクションはデフォルトのページの送信とし、データのロードはプロセスとして実装します。比較的重い処理が実行されるため、確認の要求をオンにし、確認のメッセージとして法令データをロードしますか?を設定します。
バックグラウンド実行の進捗を確認するため、ビューAPEX_APPL_PAGE_BG_PROC_STATUSを一覧する対話モード・レポートを作成します。
識別のタイトルを進捗とし、ソースのタイプをSQL問合せ、SQL問合せとして以下を記述します。
select * from APEX_APPL_PAGE_BG_PROC_STATUS
実行チェーンに小プロセスを作成します。
プロセス・ビューを開き、法令データをロードするプロセスを作成します。
最初にバックグラウンドで実行するため、実行チェーンを作成します。
プロセスを作成します。識別の名前は法令データのロード、タイプは実行チェーンとします。
設定のバックグラウンドで実行をオンにします。サーバー側の条件のボタン押下時にLOADを指定します。
識別の名前はLoad e-Gov CSV and XML、タイプはコードの実行とし、ソースの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_blob_zip blob; | |
l_blob_csv blob; | |
l_blob_xml blob; | |
l_clob_xml clob; | |
l_new_hash raw(32); | |
l_old_hash raw(32); | |
e_web_access_failed exception; | |
l_files apex_zip.t_files; | |
l_load_result apex_data_loading.t_data_load_result; | |
l_total_laws number; | |
l_id varchar2(4000); | |
l_xml xmltype; | |
l_skipped number := 0; | |
l_ignored number := 0; | |
l_updated number := 0; | |
l_message varchar2(100); | |
begin | |
/* | |
* URLで指定された法令種別データセットを取得する。ZIP形式のバイナリ。 | |
*/ | |
apex_background_process.set_status('Start: downloading zip'); | |
apex_web_service.set_request_headers('Content-Type', 'application/zip'); | |
l_blob_zip := apex_web_service.make_rest_request_b( | |
p_url => :P1_URL | |
,p_http_method => 'GET' | |
); | |
if apex_web_service.g_status_code <> 200 then | |
raise e_web_access_failed; | |
end if; | |
apex_debug.info('Download Completed.'); | |
apex_background_process.set_status('Completed: downloading zip'); | |
/* | |
* ZIPアーカイブに含まれるファイル一覧を取得する。 | |
*/ | |
l_files := apex_zip.get_files( | |
p_zipped_blob => l_blob_zip | |
); | |
/* | |
* ZIPアーカイブに含まれるCSVファイルを見つけ、表JLAW_DATAにロードする。 | |
*/ | |
apex_background_process.set_status('Start: load CSV in zip'); | |
for i in 1..l_files.count | |
loop | |
/* | |
* 含まれているCSVファイルは1つだけなはず。 | |
*/ | |
if l_files(i) like '%.csv' then | |
apex_debug.info('file %s found.', l_files(i)); | |
l_blob_csv := apex_zip.get_file_content( | |
p_zipped_blob => l_blob_zip | |
,p_file_name => l_files(i) | |
); | |
l_load_result := apex_data_loading.load_data( | |
p_static_id => 'LOAD_CSV' | |
,p_data_to_load => l_blob_csv | |
); | |
l_total_laws := l_load_result.processed_rows; | |
apex_debug.info( 'Processed %s rows.', l_total_laws); | |
exit; -- CSVがロードできれば以降はスキップしてXMLのロードに移る。 | |
end if; | |
end loop; | |
apex_debug.info('CSV Load Complated.'); | |
apex_background_process.set_status('Completed: load CSV in zip'); | |
/* | |
* ZIPに含まれているXMLを表JLAW_DATAに更新する。 | |
*/ | |
apex_background_process.set_status('Start: load XML files in zip'); | |
for i in 1..l_files.count | |
loop | |
if l_files(i) like '%.xml' then | |
l_blob_xml := apex_zip.get_file_content( | |
p_zipped_blob => l_blob_zip | |
,p_file_name => l_files(i) | |
); | |
/* 法令のXMLファイルはディレクトリ名とファイル名が同じ。 */ | |
l_id := replace(l_files(i),'.xml'); | |
l_id := substr(l_id, instr(l_id,'/')+1); | |
/* BLOBをXMLtypeに変換 */ | |
l_xml := xmltype( | |
xmlData => l_blob_xml | |
,csid => NLS_CHARSET_ID('AL32UTF8') | |
); | |
/* ハッシュ値の計算 */ | |
l_clob_xml := l_xml.getClobVal(); | |
l_new_hash := dbms_crypto.hash(l_clob_xml, dbms_crypto.HASH_SH256); | |
begin | |
select body_hash into l_old_hash from jlaw_data where id = l_id; | |
/* ハッシュ値が一致していれば更新しない。 */ | |
if l_old_hash = l_new_hash then | |
l_skipped := l_skipped + 1; | |
else | |
l_updated := l_updated + 1; | |
update jlaw_data set body = l_xml, body_hash = l_new_hash where id = l_id; | |
if mod(l_updated, 200) = 0 then | |
commit; -- 200行アップデートごとにコミットする。 | |
apex_debug.info('XML Load Commited.'); | |
end if; | |
end if; | |
exception | |
when no_data_found then | |
/* CSVにエントリがないのにXMLはあるのは異常。 */ | |
l_ignored := l_ignored + 1; | |
apex_debug.info('id %s not in CSV.', l_id); | |
end; | |
apex_background_process.set_progress(p_sofar => i ,p_totalwork => l_total_laws); | |
end if; | |
end loop; | |
commit; | |
l_message := apex_string.format('Completed: updated %s, skipped %s, ignored %s', l_updated, l_skipped, l_ignored); | |
apex_background_process.set_status(l_message); | |
apex_debug.info(l_message); | |
end; |
データベースにロードする法令データのリンクのアドレスをコピーします。
すべての法令データをデータベースにロードするには、大体1時間弱ほどの時間がかかりました。
https://github.com/ujnak/apexapps/blob/master/exports/sample-e-gov-law-loading.zip
今の所、取り込んだXML形式の法令データの使い道は思いつかないのですが、少々複雑な形式のデータをデータベースに取り込む手順の参考になるかと思います。
Oracle APEXのアプリケーション作成の参考になれば幸いです。
完