XMLファイルからPDFファイルを生成する

前回は、Apache FOPを用いてXSL-FO文書を元にPDF文書を生成する方法を紹介した。Apache FOPでは、XSL-FOを直接記述するだけでなく、XML文書からPDF文書を生成する方法も用意されている。具体的には、XML文書をXSLTを利用してXSL-FO文書に変換し、そこからPDFを生成するという形になる。したがってこの方法では、元になるXMLファイルのほかにXSLTを記述したファイルを用意する必要がある。

まずはXMLファイルを用意しよう。本稿では次のような内容を記述した「fop-sample-ja.xml」というファイルを用意した。見てのとおり、<colmun>の子要素として<title>と<abstract>を持つ構造である。

リスト1 fop-sample-ja.xml

<?xml version="1.0" encoding="UTF-8"?>
<colmun>
  <title>
    攻略! ツール・ド・プログラミング
  </title>
  <abstract>
    この連載ではプログラミングを手助けするツールやライブラリ、フレームワーク、プラットフォームなどについて紹介しています。
  </abstract>
</colmun>

これをXSL-FOに変換するXSLTとしては、次のような内容のファイルを「xml2fo-sample.xsl」という名前で作成した。

リスト2 xml2fo-sample.xsl

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:fo="http://www.w3.org/1999/XSL/Format">
  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="/colmun">

    <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
      <fo:layout-master-set>
    <fo:simple-page-master master-name="A4-portrait"
                   page-height="29.7cm" page-width="21.0cm" margin="2cm">
      <fo:region-body margin-top="1cm"/>
    </fo:simple-page-master>
      </fo:layout-master-set>

      <fo:page-sequence master-reference="A4-portrait">
    <fo:flow flow-name="xsl-region-body">
      <fo:block font-size="14pt" color="red" margin="0.5cm" font-family="IPA Mincho">
            <xsl:value-of select="title"/>
      </fo:block>
      <fo:block font-size="12pt" margin="0.5cm"  font-family="IPA Mincho">
            <xsl:value-of select="abstract"/>
      </fo:block>
    </fo:flow>
      </fo:page-sequence>
    </fo:root>

  </xsl:template>

</xsl:stylesheet>

XSLTに関する詳しい解説は省略するが、テンプレートの基本になっているのは前回の記事のfop-sample-ja.foであり、そこにfop-sample-ja.xmlの<title>要素と<abstract>要素の内容を埋め込む形になっている。すなわち、

リスト3

<xsl:template match="/colmun">

のタグで<colmun>要素にマッチする部分を探し、

リスト4

<fo:block font-size="14pt" color="red" margin="0.5cm" font-family="IPA Mincho">
  <xsl:value-of select="title"/>
</fo:block>
<fo:block font-size="12pt" margin="0.5cm"  font-family="IPA Mincho">
  <xsl:value-of select="abstract"/>
</fo:block>

の部分でその中にある<title>要素と<abstract>要素の値をそれぞれXSL-FO形式のテンプレートに埋め込んでいる。

PDFファイルの生成は、XSL-FOファイルの場合と同様にfopコマンドで行うことができる。次のように-xmlオプションでXMLファイルを、-xslオプションでXSTLファイルを指定すればよい。また、日本語フォントを使用しているので-cオプションによる設定ファイルの指定も必要となる。

プロンプト1

>fop -c conf/fop.xconf -xml fop-sample-ja.xml -xsl xml2fo-sample.xsl pdf-from-xml.pdf

コマンドが成功すれば、「pdf-from-xml.pdf」というPDFファイルが生成される。内容は図1のようになる。

図1 XMLファイルを元にXSLT経由で生成したPDFファイル

ちなみに、PDFファイルを直接生成するだけでなく、XSL-FOファイルを生成することもできる。その場合は、出力先のファイル名を次のように-fooutオプションで指定すればよい。

プロンプト2

>fop -c conf/fop.xconf -xml fop-sample-ja.xml -xsl xml2fo-sample.xsl -foout fo-from-xml.fo

JavaプログラムからApache FOPを利用する

次に、JavaプログラムからApache FOPを利用してみよう。まずはXSL-FOファイルからPDFファイルを生成するプログラムを作ってみる。JavaプログラムでApache FOPを利用するには、buildフォルダにあるfop.jarと、libフォルダにある各種jarファイルをクラスパスに含めてコンパイル/実行を行う必要がある。特に、XSLの扱いにはJAXP APIを利用するためxml-apis-xxxx.jarは必須となる。

以下に、fop-sample-ja.fo(前回使ったXSL-FOファイル)を読み込み、fop-sample-ja.pdfを出力するプログラムの例を示す。 インポートしているクラスのうち、javax.xml.transformおよびorg.xml.saxパッケージのものはJAXP APIに含まれるクラスで、org.apache.fop.appsパッケージのものはApache FOPで提供されるクラスである。

リスト4

import java.io.*;

import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamSource;
import org.xml.sax.SAXException;

import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.Fop;
import org.apache.fop.apps.FopFactory;
import org.apache.fop.apps.MimeConstants;

public class Fo2PdfSample {
    public static void main(String[] args) {
    // FopFactoryオブジェクトの取得
    FopFactory fopFactory = FopFactory.newInstance();

        try {
            // 日本語フォントの設定の追加
            fopFactory.setUserConfig("[PATH_TO_FOP]/conf/fop.xconf");

            // 出力先の指定
            OutputStream output = new BufferedOutputStream(new FileOutputStream("fop-sample-ja.pdf"));

        // 出力フォーマットを指定してFopオブジェクトを生成
        Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, output);

        // XSL-FOファイルの指定
        Source source = new StreamSource("fop-sample-ja.fo");

        // 変換用オブジェクトの生成
        TransformerFactory factory = TransformerFactory.newInstance();
        Transformer transformer = factory.newTransformer();

        // 結果格納用のResultオブジェクトを生成
        Result result = new SAXResult(fop.getDefaultHandler());

        // 変換を実行
        transformer.transform(source, result);

            output.close();
        } catch (FOPException ex) {
            ex.printStackTrace();
        } catch (SAXException ex) {
            ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        } catch (TransformerConfigurationException ex) {
            ex.printStackTrace();
        } catch (TransformerException ex) {
            ex.printStackTrace();
        }
    }
}

PDFの生成を行うのに重要なのはFopクラスだが、FopオブジェクトはFopFactoryオブジェクトから生成する。日本語フォントを使う場合などは、setUserConfigメソッドを使ってFopFactoryに設定ファイルを指定しておく。Fopオブジェクトの生成はnewFopメソッドで行える。このメソッドの引数には、出力フォーマット(MIMEタイプ)と出力先のストリームオブジェクトを指定する。出力フォーマットの指定にはMimeConstantsクラスが利用できる。

元になるXSL-FOファイルはSourceオブジェクトとして読み込む。今回はファイルストリームから読み込むためにStreamSourceを使っている。実際のPDFの出力にはTransformerクラスに用意されたをtransformメソッドを使用する。このメソッドはXML関連のファイルのフォーマット変換を行うためのもので、第1引数にSourceオブジェクトを、第2引数に結果を格納するためのResultオブジェクトを渡して実行する。

本稿の例では、Resultオブジェクトをfop.getDefaultHandlerメソッドの結果を元にして作成している。これによって、Resultに渡された結果がFopオブジェクトのハンドラで処理され、PDFファイルとして出力されるようになる。

このプログラムをコンパイル/実行すると、fop-sample-ja.pdfというPDFファイルが出力される。内容は図1に示したものと同様になる。