PR TIMESデザイナー&エンジニアブログ BREAK TIMES

PR TIMES Developer Blog(デザイナー&エンジニアによる開発者ブログ)

PR TIMES Developer Blog
デザイナー&エンジニアによる開発者ブログ

Apache POIでOffice文書を生成してみる

プログラムでOfficeの文書を生成する為にはどのようにしたらいいでしょうか。
プログラムを動作させるコンピュータが、Windowsであれば、COMオブジェクトを使用してExcelを出力するのはなんとなく出来そうです。
でも、例えばLinuxExcelを作成する場合はそれは使えません。
そもそも、Office文書はどんなふうにファイルを作成したら良いのでしょう。

調べてみると、Excel97-2003までのファイルはある特定の形式でファイルを作成すれば良さそうです。

[MS-XLS]: Excel Binary File Format (.xls) Structure

これを一から分析してファイルを作っていくのは不可能とは言わないまでも相当な手間が掛かりそうです。
ちなみに、Office 2007からは、Office Open XML(OOXML)という形式のXMLファイルになったので、こちらなら頑張れば自力で作ることも出来そうではあります。

Apache POI

f:id:breaktimes:20140625150846j:plain
Apache POIは、JavaからOffice文書を作成することが出来るライブラリです。
かなり昔から開発が続けられていましたが、一度開発はストップしたこともあります。(jarファイルのバージョン番号のところに「FINAL」と入れているのはその名残ではなかろうか・・・)
しかしその後復活し、2014/6現在でのSubversionを見てみると比較的活発に開発が続けられているようです。
現在はなんとVisioの文書を読めるようになったり、まだまだ機能も追加されそうです。

phpにもPHPExcelrubyでもspreadsheet等がありますが、
POIに比べるとあまり小回りが効かない印象が筆者にはあります。
文書の生成等はPOIで行って、それをLL系言語で呼び出して使うのが現実的な使い方の一つではないでしょうか。

今回の動作環境

Windows 7 32bitでjavaは下記のバージョンをインストールしています。
開発はEclipseを使っています。

$ java -version
java version "1.7.0_60"
Java(TM) SE Runtime Environment (build 1.7.0_60-b19)
Java HotSpot(TM) Client VM (build 24.60-b09, mixed mode)

POIのダウンロード

Apache POI - Download Release Artifactsにダウンロードのリンクがあるので、そこから
poi-bin-3.10-FINAL-20140208.tar.gzを今回は使用しました。
これを解凍すると、下記のようなファイルが展開されます。

$ ls -la
合計 9360
drwxrwxrwx+ 1 prtimes Domain Users       0 6月  25 11:18 .
drwxrwxrwx+ 1 prtimes Domain Users       0 6月  25 11:18 ..
drwxrwxrwx+ 1 prtimes Domain Users       0 6月  25 11:18 docs
drwxrwxrwx+ 1 prtimes Domain Users       0 6月  25 11:18 lib
-rwxrwxrwx+ 1 prtimes Domain Users   27254 1月  16 13:37 LICENSE
-rwxrwxrwx+ 1 prtimes Domain Users     890 1月  16 13:37 NOTICE
drwxrwxrwx+ 1 prtimes Domain Users       0 6月  25 11:18 ooxml-lib
-rwxrwxrwx+ 1 prtimes Domain Users 1950905 2月   1 23:00 poi-3.10-FINAL-20140208.jar
-rwxrwxrwx+ 1 prtimes Domain Users  312839 2月   1 23:00 poi-examples-3.10-FINAL-20140208.jar
-rwxrwxrwx+ 1 prtimes Domain Users   30530 2月   1 23:00 poi-excelant-3.10-FINAL-20140208.jar
-rwxrwxrwx+ 1 prtimes Domain Users 1031421 2月   1 23:00 poi-ooxml-3.10-FINAL-20140208.jar
-rwxrwxrwx+ 1 prtimes Domain Users 4946671 2月   1 23:00 poi-ooxml-schemas-3.10-FINAL-20140208.jar
-rwxrwxrwx+ 1 prtimes Domain Users 1240093 2月   1 23:00 poi-scratchpad-3.10-FINAL-20140208.jar

Excel文書の生成

Excel文書の作成は、POIではHSSF、XSSFというフォーマット名で扱います。
HSSFはOffice 97-2003までのバイナリ形式のもの、XSSFは、最近のOOXMLのことです。
今回は、HSSFを使ってサンプルのExcel文書を生成しています。
クラスパスにはpoi-3.10-FINAL-20140208.jarを含めます。

これを実行するために、HSSFSampleというクラスを作りました。

package poi;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;

public class HSSFSample {
  
  public static final void main(String[] args) {
    HSSFWorkbook wb = new HSSFWorkbook();
    
    HSSFSheet s1 =  wb.createSheet("サンプルシート1");
    
    String[] headerValues = {"列1","列2","合計"};
    int[][] rowValues = {{1,1},{2,2},{3,3},{4,4},{5,5},};
    HSSFRow headerRow = s1.createRow(0);
    
    for (int i=0; i<headerValues.length; i++ ){
      HSSFCell c = headerRow.createCell(i);
      c.setCellValue(headerValues[i]);
    }
    
    for (int i=0; i<rowValues.length; i++ ){
      HSSFRow valueRow = s1.createRow(i+1);
      for (int j=0; j<rowValues[i].length; j++) {
        HSSFCell c = valueRow.createCell(j);
        c.setCellValue(rowValues[i][j]);
      }
      HSSFCell c =valueRow.createCell(2);
      int rowNumber = i+2;
      c.setCellFormula(String.format("A%d*B%d", rowNumber, rowNumber));
    }
    
    
    HSSFSheet s2 =  wb.createSheet("サンプルシート2");
    HSSFSheet s3 =  wb.createSheet("サンプルシート3");
    
    try {
      wb.write(new FileOutputStream(new File("sample1.xls")));
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
  
}

ワークブックを生成して、シートを三枚追加し、1シート目にセルの値と、Excelの計算式を入れてみました。
これをExcelで開くとこのようになります。

f:id:breaktimes:20140625151659p:plain

これだけでもかなり簡単に生成出来る雰囲気が伝わるのではないでしょうか。

Word文書の生成

Excelと同様に、Word97-2003形式のファイルを操作するためのHWPFというのがあるのですがこちらはネットでのサンプルも少なく、
HSSFと同様にサンプルコードを書いてみたのですが何もないところからWordの文書を作成し、保存するのがうまく行きませんでした。
なので、Word文書の作成は、OOXML形式のサンプルを動作させてみたいと思います。
OOXML形式のWord文書はXWPFというフォーマットでPOI内では扱っています。

OOXML形式のファイルを扱うには、poi-ooxml-3.10.FINAL-20140208.jarが必要で、それに依存するpoi-ooxml-schemas-3.10.FINAL-20140208.jar
また、ooxml-lib以下のjarが必要になりますので、それらをクラスパスに追加します。
まとめると下記のjarファイルが必要です。

  • poi-ooxml-3.10.FINAL-20140208.jar
  • poi-ooxml-schemas-3.10.FINAL-20140208.jar
  • ooxml-lib/dom4j-1.6.1.jar
  • ooxml-lib/stax-api-1.0.1.jar
  • ooxml-lib/xmlbeans-2.3.0.jar

動作させるために、XWPFSampleというクラスを作成しました。

package poi;

import java.io.FileOutputStream;

import org.apache.poi.xwpf.usermodel.ParagraphAlignment;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;

public class XWPFSample {

  public static void main(String[] args) throws Exception {
    XWPFDocument doc = new XWPFDocument();
    XWPFParagraph header = doc.createParagraph();
    header.setAlignment(ParagraphAlignment.CENTER);
    XWPFRun run = header.createRun();
    run.setText("サンプル文書");
    
    doc.write(new FileOutputStream("sample1.docx"));
  }

}

流れとしては、XWPFDocumentを作成し、パラグラフを作成、そのパラグラフに対してスタイルやテキストを設定していく感じで作成できます。

f:id:breaktimes:20140625151717p:plain

PowerPoint文書の生成

Powerpointも、POIで扱うフォーマットとしては、HSLF/XSLFというのがありますので、同様に作ってみます。
HSLFを扱うクラスは、poi-scratchpad-3.10.FINAL.20140208.jarに入っているので、それをクラスパスに追加します。

package poi;

import java.io.File;
import java.io.FileOutputStream;

import org.apache.poi.hslf.model.Picture;
import org.apache.poi.hslf.model.Slide;
import org.apache.poi.hslf.model.TextBox;
import org.apache.poi.hslf.usermodel.SlideShow;

public class HSLFSample {

  public static void main(String[] args) throws Exception {
    SlideShow ss = new SlideShow();
    
    Slide s1 = ss.createSlide();
    TextBox title = s1.addTitle();
    title.setText("サンプル文書");
    
    int picIndex = ss.addPicture(new File("project-logo.jpg"), Picture.JPEG);
    Picture logo = new Picture(picIndex);
    
    s1.addShape(logo);
    
    ss.write(new FileOutputStream(new File("sample.ppt")));
  }

}

スライドを作成し、タイトルと、POIのロゴを追加しています。
HWPF/XWPFよりは、HSLFのほうが感覚的にわかりやすいかなと感じました。

f:id:breaktimes:20140625151727p:plain

まとめ

現実的にはOffice文書で作成したい、扱いたいという要望は現場では多数あるのではないでしょうか。
プログラムからOfficeの文書を扱うには、OOXML形式だとしてもフォーマットの理解などが必要になります。
この辺りをうまく抽象化してくれているのがPOIです。
例では簡単な例しかご紹介していませんが、HSSFなどはかなり細かいところまで調整することが出来るのは嬉しいところです。

なお今回のサンプルコードはgithubに上げてあります。
よろしければサンプルを色々動かしてみてください。

https://github.com/kyokoshima/poi-example