.XLSXファイルの準備:PL / SQLを使用してファイルを編集する

パート1 はじめに、スタイル

パート2 行、マークアップ

パート3 PL / SQLを介した編集



良い一日 XLSX形式に関する会話の3番目の部分が到着しました。 ファイルの内部デバイスから始めたのは偶然ではありませんでした。 それがどこにあり、どのように見えるかを理解していないので、なぜ私がこれとそれをしたのかを理解することは困難です。 さらに、いくつかのコメントを作成できるようになりました。



最初のもの。 必要な要素について言及しなかった場合は、空のXLSXファイルを作成し、必要な要素を作成して保存します。 これで、この要素を定義するコードを探す場所がわかりました。



二番目。 OpenXMLは、タグ構造に違反しない場合、マークアップ内の任意のテキストを許可します(これを非常に積極的に使用します)。 次に説明します。 これを行うことができます:



<sst xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"> <si><t> </t></si> <si><t> </t></si> $  $ </sst>
      
      





しかし、このように-あなたはできません:



 <sst xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"> <si><t> </t></si> <si><t> </t></si> <  > </sst>
      
      





しかし、ポイントに。 厳密に言えば、2つのケースが考えられます。 データを入力する必要がある特定のテンプレートがあるか、彼らが言うように、ゼロからファイルを作成する必要があります。 最初のケースはより単純で、2番目のケースはより興味深いものです。 ただし、この場合、どちらの場合もスタブファイルが必要です。.XLSXファイルは.XMLファイルだけで構成されているわけではないため、残念ながら「手」では機能しません。



一般に、私が使用する方法論は、主にAlexandria PL / SQLライブラリに基づいています 。 ライブラリ自体は巨大であり、以下で説明する目的を除き、必要ない場合は、選択的に埋め込む方が良いでしょう。



購読者の領収書の形で簡単に代替するには、このライブラリに提示された資金で十分です。 詳細を考慮して、アドオンを追加する必要がありました。 したがって、読み始めたら、最後まで読むことをお勧めします。おそらく、私の解決策はあなたにとってより便利または効果的だと思うでしょう。 アクションの一般的なアルゴリズムは次のとおりです。



  1. BLOBでファイルの準備を変換します。
  2. XMLファイル内の条件付きラベルをデータで置き換えます。
  3. 変更したBLOBを新しいファイルとして保存します。
  4. 変更したファイルをユーザーに返します。


これらのポイントをさらに詳しく見ていきましょう。 ライブラリツールと汎用ツールを区別するために、ライブラリコードを投機パッケージlib_utilsに配置したと想像してください



ワークファイルをBLOBに変換します



購読者の名前と支払額を挿入する必要がある領収書などのフォームがある場合、すべては簡単ではありません。完成した領収書を取得し、変数フィールドの内容を特別なビーコンタグに変更します。 これらのビーコンのテキストに関する2つの基本的なルールがあります。タグを模倣してはならず、ドキュメントのソーステキストまたは置換テキストの偶然の可能性は無視できるほど小さいはずです。 そうでなければ、それはすべてあなたの想像力や習慣に依存します。 %name%のようなものを使用しています。 理由を説明します。 「%」記号はマークアップを模倣しておらず、この記号によってこの側でどこか別の単語が存在する可能性はごくわずかです。



ただし、出力ファイルに何が含まれているかが事前にわからない場合は、さらに作業が必要になります。



何よりもまず、Excelを使用して、必要なすべてのセルスタイルを指定することをお勧めします(必要ない場合は、大丈夫です。何か不足している場合よりも良いです)。 その後、メモ帳でノートブックに登り、特定のスタイルのインデックスを書き留めます。 そこで、見出し(灰色の塗りつぶし、太字のスペル、細い境界線)のスタイルと行の行(塗りつぶしなし、通常のスペル、細い境界線)のスタイルを別々にしました。



その後、Excelではなく、手で作業する必要があります。



sharedStrings.xmlファイルは次のようになります。



 <sst xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"> %strings% </sst>
      
      





ファイルsheet1.xml (メインシートとして最初のシートがあると仮定)には、次が含まれている必要があります。



 <sheetViews> <sheetView tabSelected="1" workbookViewId="0"> %attach% </sheetView> </sheetViews> <sheetFormatPr defaultRowHeight="15" x14ac:dyDescent="0.25"/> %colsize% <sheetData> %data% </sheetData> %filter%
      
      





ラベル%attach%は、タグをエリアに取り付ける場所にあります。 ラベル%colsize% -占有列の幅を示すタグの位置。 これは、たとえば、名前列の幅が適切になるように行われます。 %data%ラベルは、生成されたセルマークアップに置き換えられます。 ラベル%filter% -オートフィルターを埋め込む必要がある場合。



保存して閉じます-ディスクの準備ができました。 次に、それをBLOBに変換する必要があります。 これを行うには、ライブラリ関数lib_utils.get_blob_from_fileが必要です念のため、lib_utilsは投稿の冒頭のリンクからライブラリの関数であることを思い出させてください)。 この関数は、ディレクトリとファイル名の2つのパラメーターを取ります。 これは少し明白ではないので、ディレクトリはOracle DIRECTORYオブジェクトであることを説明します。 この例では、ディレクトリFILE_DIRを呼び出しましょう。 つまり、呼び出しは次のようになります。



 --  ,         -  v_blobsrc := lib_utils.get_blob_from_file('FILE_DIR', 'src_blank.xlsx');
      
      





ラベルをカスタムデータで置き換える



領収書フォームを使用した単純なケース(または同様のケース)では、 lib_utils.multi_replace関数を使用します。 ライブラリはあなたのためにすべてを行います。



難しい場合のために、私は自分の建設を構築しました。 これは、複合手書きデータタイプに基づいています。これは、Excelワークシートの内容の包括的な説明です。 タイプは複合型であるため、下から上へ行きましょう。



 /* :  */ type tp_cell is record(address varchar2(15), style number, val varchar2(4000), lines number default 1); /* :  */ type tp_row is table of tp_cell index by binary_integer; /* :  () */ type tp_table is table of tp_row index by binary_integer; /* :      */ type tp_string is table of varchar2(4000) index by binary_integer; type tp_number is table of number index by binary_integer;
      
      





後者のタイプはtp_tableの構築に直接関与しませんが、とにかくまだ必要です。 tp_cell型の要素について説明します。





ファイル作成ルーチンの最終的な署名は次のようになります。



 file_build(i_content tp_table, i_filename varchar2, i_filter number default 0, i_attach number default 0);
      
      





このプロシージャは、次のパラメータを取ります。





そして、メイン手順の詳細な分析を開始する前に、補助機能をレイアウトします。



ヘルパー関数
 /*     (  Excel) */ function get_literal(i_number number) return varchar2 is begin --    if i_number < 1 or is_number(i_number) = false then return '#'; -- 1-  elsif i_number > 0 and i_number < 29 then return chr(64 + i_number); -- 2-  else return chr(64 + trunc(i_number / 28))||chr(64 + (i_number - (28 * trunc(i_number / 28)))); end if; end get_literal; /* :    */ function is_number(i_char char) return boolean is begin if (to_number(i_char) = to_number(i_char)) then return true; end if; exception when others then return false; end is_number; /*     */ function array_search(i_source tp_string, i_value varchar2) return number is begin for i in 1 .. i_source.count loop if i_value = i_source(i) then return i; end if; end loop; return -1; end array_search; /*  ""  ( 32767 )   CLOB-    */ procedure clob_append(i_dest in out clob, i_src in varchar2, i_encode in varchar2 default 'utf8') is begin if i_src is not null then if i_dest is null then i_dest := to_clob(convert(i_src, i_encode)); else dbms_lob.write(i_dest, length(convert(i_src, i_encode)), length(i_dest) + 1, convert(i_src, i_encode)); end if; end if; end clob_append;
      
      







何かを明確にしたいだけです。 ファイルには大量のデータが含まれている可能性があるため、varcharに似たタイプを扱うことは不可能であり、単に十分ではありません。 したがって、CLOBの下で決定を明確にする必要があります。 一般的に、これまでのところ、超自然的なことは何もありません。 しかし、ポイントに。



基本手順
 procedure build_file(i_content tp_table, i_filename varchar2, i_filter number default 0, i_attach number default 0) is v_blobsrc blob; --    BLOB v_blobres blob; --    BLOB c_namesrc constant varchar2(50) := 'src_blank.xlsx'; --  - v_stringarr tp_string; --     v_numarr tp_number; --    v_index number; --     v_clobmarkup clob; --   v_clobstring clob; --  sharedStrings.xml v_clobcolumns clob; --    c_letsize constant number := 3; --  1   .. c_padding constant number := 1; --    v_rowcount number; --  -  v_colcount number; --  -  v_multiline number; --  v_filtertag varchar2(50); --    v_attachtag varchar2(150); --     begin /*      */ for l_row in 1 .. i_content.count loop v_rowcount := l_row; --   DIMENSION /* ,      .  ,         */ v_multiline := 1; for l_col in 1 .. i_content(l_row).count loop if i_content(l_row)(l_col).lines > v_multiline then v_multiline := i_content(l_row)(l_col).lines; end if; end loop; clob_append(v_clobmarkup, '<row r="'||l_row||'"'||case when v_multiline > 1 then ' ht="'||(15 * v_multiline)||'" customHeight="1"' else null end||'>'||chr(10)); /*      */ for l_cells in 1 .. i_content(l_row).count loop v_colcount := l_cells; --   if i_content(l_row)(l_cells).val is null then clob_append(v_clobmarkup, '<cr="'||i_content(l_row)(l_cells).address||'" s="'||i_content(l_row)(l_cells).style||'"><v></v></c>'||chr(10)); else --      if is_number(i_content(l_row)(l_cells).val) then clob_append(v_clobmarkup, '<cr="'||i_content(l_row)(l_cells).address||'" s="'||i_content(l_row)(l_cells).style||'"><v>'||i_content(l_row)(l_cells).val||'</v></c>'||chr(10)); else /*   : "-1" -  ,          */ v_index := array_search(v_stringarr, i_content(l_row)(l_cells).val); if v_index = -1 then v_index := v_stringarr.count + 1; v_stringarr(v_index) := i_content(l_row)(l_cells).val; end if; -- --         clob_append(v_clobmarkup, '<cr="'||i_content(l_row)(l_cells).address||'" s="'||i_content(l_row)(l_cells).style||'" t="s"><v>'||(v_index - 1)||'</v></c>'||chr(10)); end if; end if; /*          */ if v_numarr.count >= l_cells then if length(i_content(l_row)(l_cells).val) > v_numarr(l_cells) then v_numarr(l_cells) := length(i_content(l_row)(l_cells).val); end if; elsif v_numarr.count = l_cells - 1 then v_numarr(l_cells) := length(i_content(l_row)(l_cells).val); end if; end loop; --    clob_append(v_clobmarkup, chr(10)||'</row>'); end loop; --     clob_append(v_clobcolumns, '<cols>'); for l_cnt in 1 .. v_numarr.count loop clob_append(v_clobcolumns, '<col min="'||l_cnt||'" max="'||l_cnt||'" width="'||round((v_numarr(l_cnt) * c_letsize / 2) + c_padding)||'" style="1" customWidth="1"/>'); end loop; clob_append(v_clobcolumns, '</cols>'); --     for l_cnt in 1 .. v_stringarr.count loop clob_append(v_clobstring, '<si><t>'||v_stringarr(l_cnt)||'</t></si>'||chr(10)); end loop; /*    -   */ if i_filter = 1 then v_filtertag := '<autoFilter ref="A1:'||get_literal(v_colcount)||'1"/>'; end if; if i_attach = 1 then v_attachtag := '<pane ySplit="1" topLeftCell="A2" activePane="bottomLeft" state="frozen"/>'; end if; --  v_blobsrc := lib_utils.get_blob_from_file('FILE_DIR', c_namesrc); v_blobres := lib_utils.get_file_from_template(v_blobsrc, lib_utils.t_str_array('%colsize%', '%data%', '%strings%', '%filter%', '%attach%', '<dimension ref="A1:B2"/>'), lib_utils.t_str_array(v_clobcolumns, v_clobmarkup, v_clobstring, v_filtertag, v_attachtag, '<dimension ref="A1:'||get_literal(v_colcount)||v_rowcount||'"/>')); lib_utils.save_blob_to_file('FILE_DIR', i_filename, v_blobres); exception when others then dbms_output.put_line('    Excel: '||sqlerrm); end build_file;
      
      







実際には、それだけです。 ええ、はい、私は予約をしたいです:この手順は現在のニーズに応じて定期的に補足されます。



All Articles