Hatena::ブログ(Diary)

そもさん&せっぱさん

2014-07-26

jrunscript/RhinoでLibreOffice Calcのセルの読み書き(ついでにxls,xlsxも)

WSH を使った Excelファイルの読み書きのように、「Java が入っていれば JavaScript をササッと書いて自動化できる!」みたいなお手軽環境があるといいなあと思ってやってみました。

あんまりドッグフーディングしてなくてサンプルというかデモ程度です。

必要なファイルは gist に置きました:

https://gist.github.com/sonota88/4b2232e8aa0fb25c76a9


準備

  1. LibreOffice をインストール … LibreOffice_4.2.5_Win_x86.msi
  2. LibreOffice SDK をインストール … LibreOffice_4.2.5_Win_x86_sdk.msi
  3. Java 7 をインストール … Pleiades のがすでに入っていたのでそれを使用

OS は Windows 7 64bit。


サンプルスクリプト

スクリプトとして手軽に使いたいので、UNOまわりとかの面倒なところは libo_calc.js に押し込めています。

sample.js:

// ライブラリをロード
load("libo_calc.js");
 
Calc.open(
    "C:/Users/user/foo/bar/sample.ods",
    function(doc){

    // シートの一覧を取得
    var sheets = doc.getSheets();
    // シートをイテレート
    sheets.forEach(function(sheet, i){
        puts("----------------");
        puts(i + ": " + sheet.name);
        // col, row / 文字列でセルの内容を取得
        puts("(0, 0) => " + sheet.get(0, 0));
        // セルに文字列をセット
        sheet.set(0, 0, "(0, 0) 日本語テキスト " + new Date());
        puts("(0, 0) => " + sheet.get(0, 0));
    });

    // 名前でシートを取得
    var sheet = doc.getSheetByName("Sheet1");

    puts("----------------");
    puts("(1, 1) => " + sheet.get(1, 1));
    sheet.set(1, 1, "(1, 1) " + new Date());
    puts("(1, 1) => " + sheet.get(1, 1));

    puts("----------------");
    sheet.set(1, 2, "12.34");
    // 整数として取得
    puts("getInt => " + sheet.getInt(1, 2));
    // 浮動小数として取得
    puts("getFloat => " + sheet.getFloat(1, 2));

    puts("----------------");
    var count = sheet.getInt(1, 3);
    if(isNaN(count)){
      count = 0;
    }
    sheet.set(1, 3, count + 1);
    puts("count => " + sheet.get(1, 3));

    // 上書き保存
    doc.save();
});

実行

  • libo_calc.js
  • libo_calc.bat
  • sample.js

を同じフォルダに置いて

libo_calc.bat sample.js

のように実行します。

あとはここらへんと合わせたりしていろいろできますね。


xls, xlsx でも同じように読み書きできる

当然といえば当然ですが xls, xlsx ファイルのパスを渡してやれば同じように操作できます。

(やっていることは LibreOffice 起動 → ファイル開く → セルの読み書き → 上書き保存 なので)


その他

ほんとは jjs/Nashorn(Java 8)で動かすとこまでやりたかったんですが、型絡みでエラーが出て時間がかかりそうだったので今回は見送り……。

Exception in thread "main" java.lang.RuntimeException: java.lang.NoSuchMethodException: None of the fixed arity signatures [(com.sun.star.uno.Type, java.lang.Object), (java.lang.Class, java.lang.Object)] of method com.sun.star.uno.UnoRuntime.queryInterface match the argument types [jdk.internal.dynalink.beans.StaticClass, com.sun.proxy.$Proxy0]
        at jdk.nashorn.internal.runtime.ScriptRuntime.apply(ScriptRuntime.java:382)
        at jdk.nashorn.tools.Shell.apply(Shell.java:381)
        at jdk.nashorn.tools.Shell.runScripts(Shell.java:310)
        at jdk.nashorn.tools.Shell.run(Shell.java:166)
        at jdk.nashorn.tools.Shell.main(Shell.java:130)
        at jdk.nashorn.tools.Shell.main(Shell.java:109)
Caused by: java.lang.NoSuchMethodException: None of the fixed arity signatures [(com.sun.star.uno.Type, java.lang.Object), (java.lang.Class, java.lang.Object)] of method com.sun.star.uno.UnoRuntime.queryInterface match the argument types [jdk.internal.dynalink.beans.StaticClass, com.sun.proxy.$Proxy0]
        at jdk.internal.dynalink.beans.OverloadedMethod.throwNoSuchMethod(OverloadedMethod.java:199)
        at jdk.nashorn.internal.scripts.Script$libo_calc._L44$_L48(libo_calc.js:73)
        at jdk.nashorn.internal.scripts.Script$sample_8.runScript(sample_8.js:4)
        at jdk.nashorn.internal.runtime.ScriptFunctionData.invoke(ScriptFunctionData.java:498)
        at jdk.nashorn.internal.runtime.ScriptFunction.invoke(ScriptFunction.java:206)
        at jdk.nashorn.internal.runtime.ScriptRuntime.apply(ScriptRuntime.java:378)
        ... 5 more

Linux での動作確認

追記 2014-07-28

Ubuntu Linux 14.04 64bit でも動くことを確認しました。

gist に libo_calc.sh を追加しました。

動かす前に次の2つのパッケージをインストールしました。

  • libreoffice-dev
  • openjdk-7-jdk

tasogare3710tasogare3710 2014/07/27 00:00 >型絡みでエラーが出て
nashornはindyを使っている弊害でLiveConnectの型変換周りを正しく実装できないためポリモーフィックメソッドのシグネチャにマッチすることが決してありません。(ただnashornは活発なので将来解決するかもしれません)

そのためindy側で呼び出すメソッドが見つけられずNoSuchMethodExceptionが投げられます。「None of the fixed arity signatures〜」というメッセージはそのことを説明しています。

これを回避するにはスクリプト側で正しく型変換するグルーコードを差し込んでやる必要がありますが、あまり現実的ではないのでjsからjavaを使う場合はrhinoの方が楽かと思います。
ただし、rhinoのLCはリフレクションで実装されているため呼び出し毎にセキュリティチェックが入るのでindyより遅いはずです。

sonota88sonota88 2014/07/27 18:36 Rhino と Nashorn とでこういうとこは非互換性あるんですね。。。indy や LiveConnect は自分にはほぼ未知の部分で、頂いたコメント大変参考になります。ありがとうございます。

さしあたって Java 8 or Nashorn で動かないと困るという訳ではありませんので、おとなしく Rhino 使いつつ Nashorn は様子見しようと思います。

どちらかというとパフォーマンスよりはとにかく動くこと・可搬性の方を気にしていて、あまり手数をかけずに導入できて「(7でも8でも)JRE が入っていれば動く」ことの確認が取れていると安心できていいなという感じです。

sonota88sonota88 2014/07/27 19:37 http://compute-taso.blogspot.jp/2014/03/nashornrhino-jdk8.html
> JavaClassとjava.lang.Classの変換をやっていない

これですねー

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証

リンク元