【Talend】マクロ(vba)付きExcelと連携する

はじめに

今回は、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と名付けて保存しておきます。

Set objArgs = Wscript.Arguments
runXLmacro 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つ作っておいた方が良いです。

今回は、不要とは思えど一応ラップしておきました。

'これがラッパー
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

ちなみに、今回ジョブに組み入れたいExcelは…
めちゃめちゃ簡単なサンプルなんですが、「CSV出力」ボタンを押すとcsvを吐き出すよ、というものです…

ファイル名はuser_tenpo_manager.xlsmとしてあります。

Talendのジョブを組んでいく

さて。
今回のメインとなるコンポーネントは、tSystemです。

これが、コマンド実行してくれるコンポーネントです。

色々と設定項目はありますが、とりあえず今回のケースではCommandパラメータに実行したいコマンドを文字列でセットするだけでOKです。
ベタ下書きするのもアレなんで、contextにcmdTextとして外出ししておきます。

サクサクっとジョブを組み立てます。

シンプルですね。連携テストが出来ればいいかな、という勢いです。
「初期化」のtJavaでtSystemに実行してもらうコマンドを組み立て、
tSystemでマクロ実行、
このマクロはcsvを吐くものなので、動作確認として最後に出力ファイルを読み込んでログ出力する、というフローです。

実行コマンドの組み立て

さて、後はtSystemにキックしてもらうコマンドを組み立てればおしまいです。
先程作成した、exec_macro.vbsをキックするコマンドを書きます。

このvbsは、引数を3個とり、それぞれ実行したいExcelファイルパス、実行したい関数名、出力ファイルパスとなっています。

cmd /c exec_macro.vbs user_tenpo_manager.xlsm OutputCsvWrapper user_info.csv

ですので、上記のようなコマンドを実行すればokです。
が、これではあまりに固定的すぎるので、それぞれのパラメータをcontextで外出ししておき、[初期化]tJavaで組み立てることにしました。

[初期化]tJavaの中身はこんな感じです。


context.cmdText = "cmd /c "
+ context.filePathWrapperVbs + " "
+ context.filePathTargetXlsx + " "
+ context.targetXlsxFunctionName + " "
+ context.filePathOutput;

System.out.println("コマンド=" + context.cmdText);

外出ししたcontextを繋げてるだけですね…はい。

後は、tSystemのCommandパラメータに編集した文字列を与えれば完成です!

実行する

実行して、正しく動くかを確認します。
先程外出ししたcontextには下記のように所定のパスを書いて…実行!

Excelマクロが実行されたかどうかがとても分かりにくいですが、ちゃんと動いています。

Excel vbaがキックされcsvを吐き、そのcsvの中身がログ出力されています。

 

今回は以上です。

 

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です