次は本題の2次元のSafeArrayを作り出す方法です。
JScriptとVBScript両方使う方法
<?xml version="1.0" encoding="Shift_JIS" ?> <package> <job> <script language="VBScript"><![CDATA[ Function convertToSafeArray2d(jsArray) Dim l1, l2, result l1 = jsArray.length l2 = Eval("jsArray.[0].length") ReDim result(l1, l2) For i=0 to l1 - 1 For j=0 to l2 - 1 result(i, j) = Eval("jsArray.[" & i &"].[" & j &"]") Next Next convertToSafeArray2d = result End Function ]]></script> <script language="JScript"><![CDATA[ // 2次元のJScript配列 var arr2d = [[1,2,8],[4,7,6]]; // SafeArrayに変換 var safeArray2d = convertToSafeArray2d(arr2d); printVBArray(new VBArray(safeArray2d)); // デバッグ用:VBArrayを表示 function printVBArray(vbArray) { for(var i=0; i<vbArray.ubound(1); i++) { for(var j=0; j<vbArray.ubound(2); j++) { WScript.Echo("vbArray[" + i + "," + j + "] = " + vbArray.getItem(i, j)); } } } ]]></script> </job> </package>
VBScriptの関数(convertToSafeArray)にJScriptの2次元配列(正確には配列の配列)を渡すと、1次元の場合と同様"JScriptTypeInfo"という型になるんですが、残念ながら、中身は"JScriptTypeInfo"の配列ではなく、単なるカンマ区切りの文字列になります。
これを別のアプローチで読み込む方法はないかと探したところ、以下の記事が見つかりました。
a jscript accessor within vbscript - ASP Message Board
要はEvalを駆使すれば出来るということのようだったので、これを利用したところうまく動作しました。
一方、VBScriptの2次元配列を戻り値として受け取ったJScript側では、1次元の場合と同様VBArrayを利用して読み込みを行います。
JScriptのみ使う方法
<?xml version="1.0" encoding="Shift_JIS" ?> <package> <job> <script language="JScript"><![CDATA[ function convertToSafeArray2d(jsArray2d) { try { // Excelを起動する var excelObj = new ActiveXObject("Excel.Application"); var workbook = excelObj.workbooks.Add(); var sheets = workbook.Sheets; var enumSheet = new Enumerator(sheets); // 1シート目を取得 var sheet = enumSheet.item(); // 各セルに値を設定 var i,j; for(i=0; i<jsArray2d.length; i++) { for(j=0; j<jsArray2d[i].length; j++) { var value = jsArray2d[i][j]; sheet.Cells(i+1, j+1).Value = value; } } // SafeArrayを返す return sheet.Cells(1, 1).CurrentRegion.Value; } finally { // Excelを終了する workbook.Close(false); excelObj.Quit(); } } // 2次元のJScript配列 var arr2d = [[1,2,8],[4,7,6]]; // SafeArrayに変換 var safeArray2d = convertToSafeArray2d(arr2d); printVBArray(new VBArray(safeArray2d)); // デバッグ用:VBArrayを表示 function printVBArray(vbArray) { for(var i=1; i<=vbArray.ubound(1); i++) { for(var j=1; j<=vbArray.ubound(2); j++) { WScript.Echo("vbArray[" + i + "," + j + "] = " + vbArray.getItem(i, j)); } } } ]]></script> </job> </package>
ExcelのRange.Valueが2次元のSafeArrayを返すことを利用した方法です。VBScriptが不要になる反面、Excelが必要になります。
配列を受け取って、セルに一つ一つ値をセットするというオーソドックスな方法をとっていますが、場合によっては、配列をテキストファイルに書き出して、Workbooks#OpenTextで読み込んだ方が速いかも知れません。
このテクニックを利用して出来たのが、先のエントリCSVファイルを一瞬でExcelファイルに変換する方法です。