はじめに
今回は、Talendでxlsmファイル(Excelのマクロ(vba)付きファイル)と連携する方法についてです。
Talendには、通常のExcelドキュメントから値を取得するためのコンポーネントは存在しますが、残念ながらExcel vbaはサポートされません…
ですが、それでも既存資産にマクロ付きExcelがあり、そのマクロの仕様が複雑すぎて新たに作り直すのは無理…なんとしてもこのExcelと連携する必要があるんだ!
という場面に出くわしましたので、今回まとめておきます。
Excel vbaと連携するTalendコンポーネントはない
前述の通り、Excelに書かれたマクロ(vba)を実行するコンポーネントはありません。
が、大丈夫です。
かなり泥臭くはありますが、Talendにはコンソールを起動するコンポーネントがあるので、それを使った方法で戦います。
ちなみに、この記事を書くにあたって、komlogさんの記事が大変参考になりました。ありがとうございます。
実装する
コマンドラインからでも、Excelの中のvba(で書かれた関数)は直接起動できないようです。
ので、vba起動用のvbsを作成し、それを経由して間接的にvbaを実行する戦略でいきます。
vbaキック用vbsを作る
以下をコピペして、exec_macro.vbsと名付けて保存しておきます。
[vb] Set objArgs = Wscript.ArgumentsrunXLmacro objArgs(0), objArgs(1), objArgs(2)
Function runXLmacro(BookName, MacroName, Parameters)
Dim XL
Set XL = CreateObject("Excel.Application")
XL.Visible = True
XL.Workbooks.Open BookName
XL.Run MacroName, Parameters
XL.ActiveWorkbook.Close False
XL.Quit
Set XL = Nothing
End Function
内容は、コマンドラインから引数を3個受け取り、Excelファイルを実行する、というものです。
パラメータに関しては後述します。
必要に応じて実行する関数のラッパーを作っておく
実行したいマクロ付きExcelが、複数の関数を実行する必要があったりする場合は、外から呼び出すためのラッパーを1つ作っておいた方が良いです。
今回は、不要とは思えど一応ラップしておきました。
[vb] ‘これがラッパーSub OutputCsvWrapper(file_path)
OutputCsv file_path, 2
End Sub
‘
‘これがラップされる側
‘概要:シートよりCSV形式テキストファイルを書き出す
Sub OutputCsv(file_path, sheet_id)
‘初期化
Dim LAST_LINE As Long
Dim FIRST_COL As Integer: FIRST_COL = 1
Dim LAST_COL As Integer: LAST_COL = 4
Dim row As Integer: row = 1
Dim col As Long
Dim out_file_num As Integer
‘ Sheetのアクティブ化
Sheets(sheet_id).Activate
‘ 収容最終行の判定
LAST_LINE = 32
‘ FreeFile値の取得
out_file_num = FreeFile
‘ 指定ファイルをOPEN(出力モード)
Open file_path For Output As #out_file_num
‘ファイル出力
‘ 最終行まで繰り返す
Do Until row > LAST_LINE
For col = FIRST_COL To LAST_COL
Write #out_file_num, Cells(row, col).Value;
Next col
Write #out_file_num, ""
‘ 行を加算
row = row + 1
Loop
‘ 指定ファイルを閉じる
Close #out_file_num
End Sub
[/vb]ちなみに、今回ジョブに組み入れたいExcelは…
めちゃめちゃ簡単なサンプルなんですが、「CSV出力」ボタンを押すとcsvを吐き出すよ、というものです…
ファイル名はuser_tenpo_manager.xlsmとしてあります。
Talendのジョブを組んでいく
さて。
今回のメインとなるコンポーネントは、tSystemです。
これが、コマンド実行してくれるコンポーネントです。
色々と設定項目はありますが、とりあえず今回のケースではCommandパラメータに実行したいコマンドを文字列でセットするだけでOKです。
ベタ下書きするのもアレなんで、contextにcmdTextとして外出ししておきます。
サクサクっとジョブを組み立てます。
シンプルですね。連携テストが出来ればいいかな、という勢いです。
「初期化」のtJavaでtSystemに実行してもらうコマンドを組み立て、
tSystemでマクロ実行、
このマクロはcsvを吐くものなので、動作確認として最後に出力ファイルを読み込んでログ出力する、というフローです。
実行コマンドの組み立て
さて、後はtSystemにキックしてもらうコマンドを組み立てればおしまいです。
先程作成した、exec_macro.vbsをキックするコマンドを書きます。
このvbsは、引数を3個とり、それぞれ実行したいExcelファイルパス、実行したい関数名、出力ファイルパスとなっています。
[text] cmd /c exec_macro.vbs user_tenpo_manager.xlsm OutputCsvWrapper user_info.csv[/text]
ですので、上記のようなコマンドを実行すればokです。
が、これではあまりに固定的すぎるので、それぞれのパラメータをcontextで外出ししておき、[初期化]tJavaで組み立てることにしました。
context.cmdText = "cmd /c "
+ context.filePathWrapperVbs + " "
+ context.filePathTargetXlsx + " "
+ context.targetXlsxFunctionName + " "
+ context.filePathOutput;
System.out.println("コマンド=" + context.cmdText);
[/java]
外出ししたcontextを繋げてるだけですね…はい。
後は、tSystemのCommandパラメータに編集した文字列を与えれば完成です!
実行する
実行して、正しく動くかを確認します。
先程外出ししたcontextには下記のように所定のパスを書いて…実行!
Excelマクロが実行されたかどうかがとても分かりにくいですが、ちゃんと動いています。
Excel vbaがキックされcsvを吐き、そのcsvの中身がログ出力されています。
今回は以上です。