SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

特集記事

TeX→PDF変換ツールを利用したバッチ処理による帳票出力

TeXのテンプレートからPDF帳票を自動生成するバッチプログラムの作成


  • X ポスト
  • このエントリーをはてなブックマークに追加

業務システムでは、帳票などの定型書類の出力が必ずと言って良いほど要件に含まれます。本稿では、TeXをPDFに変換するプログラム(dvipdfmx)を利用して、PDFファイルを出力する方法を解説します。TeXの出力にはテンプレートを用意し、必要な部分だけ書き換えて出力します。

  • X ポスト
  • このエントリーをはてなブックマークに追加

はじめに

 業務システムでは、帳票などの定型書類の出力が必ずと言って良いほど要件に含まれます。方法はいろいろ考えられますが、本稿ではPDFによる出力方法を紹介します。とはいってもPDFを直接出力するのではなく、TeXをPDFに変換するプログラム(dvipdfmx)があるのでそれを利用します。TeXの出力にはテンプレートを用意し、必要な部分だけ書き換えて出力します。

対象読者

  • .NETでシステム開発される方。
  • PDF出力に興味のある方。

必要な環境

  • Visual Studio .NET
  • TeX(「platex.exe」「dvipdfmx.exe」が動作すること)

概要

全体フローチャート
全体フローチャート

 作成するプログラムは、「文字列をパラメタで置き換えるプログラム」と「各プログラムをバッチ実行するプログラム」の2本です。入力ファイルは、「TeXテンプレート」と「変換パラメタXML」の2種類です。TeXテンプレートは1つですが、変換パラメタXMLの方は出力ファイルの数だけ用意します。バッチ実行プログラムは、変換パラメタXMLがあるフォルダから全てのファイル名を取得し、ファイルごとに決められた手順でプログラムを実行します。

 なお、株式会社オンネット・システムズ(以下、弊社)では、UIを持たないプログラムのメイン処理は独立したThreadで実行し、Formにログを出力しながら処理を進める形になっています。これは弊社での標準的な手法(以下、オンネット標準)なのでそのようにしていますが、通常のコンソールアプリケーションにしてしまっても問題はありません。メインの処理は、各cmp~クラスのRun~()メソッドに記述してあります。

文字列置換プログラム

 このプログラムは以下のような動作をします。

  1. テンプレートファイルを読み、プレースホルダを検索する。
  2. 見つかったプレースホルダの名前に対応する値をパラメタから取得する。
  3. プレースホルダを対応するパラメタ値で置き換える。
  4. 全てのプレースホルダを置き換えた後、指定したファイルに出力する。

 プレースホルダは「$$~$$」のように定義しています。「~」の部分がプレースホルダの名前にあたります。これを対応するパラメタで置き換えます。

文字列置き換え処理
System.Text.RegularExpressions.Regex regパラメタ
    = new System.Text.RegularExpressions
        .Regex(@"\$\$(?<PARAM>[^(\$\$)]+)\$\$");
for (int i = 0; i < list入力ファイル.Count; i++)
{
    string strTemp = list入力ファイル[i].ToString();

    strTemp = regパラメタ.Replace(
        strTemp,
        new System.Text.RegularExpressions
            .MatchEvaluator(Capパラメタ)
        );

    if (strTemp.IndexOf("$$") >= 0)
    {
        throw (
            new Exception(
                "対になる $$ が存在しません。["
                + list入力ファイル[i].ToString() + "]")
            );
    }

    list入力ファイル[i] = strTemp;
}

 list入力ファイルArrayListです。テンプレートファイルの各行が文字列として入っています。ここでは正規表現を利用した置換を行っています。また、置換処理後に「$$」が残っている場合はテンプレートファイルのエラーとみなし、例外をthrowしています。この部分のポイントは2つです。

 まずは正規表現ですが、プレースホルダ名にあたる部分をグループ名にキャプチャしています。簡単に説明すると、丸型カッコで括った部分がグループ、「<?~>」の「~」の部分がグループ名になります。ソースコードを見ていただくと、グループ名にPARAMと付けてあるのが分かると思います。グループのキャプチャについては、MSDNライブラリの『正規表現言語要素』に詳しい解説があります。キャプチャしたグループの取得については後述します。

 次に置換処理ですが、RegexReplace()メソッドにMatchEvaluatorの新しいインスタンスを渡しています。MatchEvaluatorは引数にMatchオブジェクトを受け取りstringを返すdelegateです。正規表現のパターンにマッチした部分をメソッドを通して置換処理します。

文字列置き換え処理サブメソッド
private string Capパラメタ
    (System.Text.RegularExpressions.Match matchパラメタ)
{
    string strパラメタ名 = matchパラメタ.Groups["PARAM"].Value;
    System.Data.DataRow[] dr変換パラメタ
        = ds変換パラメタ.Tables["パラメタ"].Select("パラメタ名 = '"
            + strパラメタ名 + "'");
    string strパラメタ値 = "";
    if (dr変換パラメタ.Length > 0)
    {
        strパラメタ値 = dr変換パラメタ[0]["パラメタ値"].ToString();
    }
    return strパラメタ値;
}

 まずはプレースホルダ名ですが、パターン文字列でPARAMと名付けたグループをプレースホルダ名として取得しています。ds変換パラメタDataSetです。パラメタという名前のDataTableを含み、その中にはパラメタ名パラメタ値の2つのDataColumnがあります。パラメタ名がプレースホルダ名と一致するレコードを探し、パラメタ値で置き換えます。DataTableSelect()メソッドはSQLのwhere句にあたる文字列を引数に渡すと、条件に当てはまるレコードをDataRowの配列で返します。ここでは1行以上見つかったら最初に見つかったDataRowパラメタ値を使用し、見つからなかった場合はEmptyで置き換えることにしています。ds変換パラメタは前述した変換パラメタXMLから生成します。

変換パラメタXMLの例
<?xml version="1.0" encoding="shift_jis" ?>
<変換パラメタ>
  <パラメタ>
    <パラメタ名>辞令番号</パラメタ名>
    <パラメタ値>000001</パラメタ値>
  </パラメタ>
  <パラメタ>
    <パラメタ名>施行年月日</パラメタ名>
    <パラメタ値>2005年10月1日</パラメタ値>
  </パラメタ>
</変換パラメタ>

 これをDataSetReadXml()メソッドで読み込みます。すると、DataSet内には次のようなDataTableが生成されます。

パラメタ
パラメタ名パラメタ値
辞令番号000001
施行年月日2005年10月1日

 これで、文字列置換プログラムの全容がつかめたかと思います。プレースホルダの検索に正規表現を使い、プレースホルダ名に対応するパラメタの取得にはDataSetの機能を利用しています。

 参考までに、オプションには以下のものが指定できます。

  • /入力ファイル=入力ファイル名
  • /変換パラメタ=変換パラメタファイル名
  • [/出力ファイル=出力ファイル名]
  • [/log=ログファイル名]

 入力ファイル名と変換パラメタファイル名の指定は必須です。出力ファイル名が省略された場合は入力ファイル名に「_conv_」と日付を付加して出力します。

バッチ実行プログラム

 このプログラムは変換パラメタXMLごとにプログラムを順次実行します。実行前に変換パラメタXMLを取得するパスやTeXテンプレートとTeXモジュールの存在チェックを行います。また、本プログラムは中間ファイル(.tex、.dvi)を出力するのでその出力先のパスもチェックします。全てのパス情報は「System.ini」ファイルに記述します(オンネット標準)。

「System.ini」
[格納フォルダ]
LogPath=Log\
TemplatePath=Template\
XmlPath=XML\
DocPath=Doc\
TeXPath=C:\usr\local\bin\
TeXWorkPath=C:\usr\local\work\

 中間ファイルの出力先フォルダ(「TeXWorkPath」)はTeX関連のプログラムが正しく認識できる場所を指定します。2バイト文字やスペースが含まれると正常動作は期待できません。

 本プログラムは

  1. 文字列変換プログラム
  2. pLaTex
  3. dvipdfmx

 の順にプログラムを実行します。各プログラム実行時には、以前の処理による中間ファイルが残っていれば削除し、プログラム実行後に中間ファイルが出力されているかどうかを確認しています。中間ファイルが出力されていることを確認してから次のプログラムの実行に移っています。

 各プログラムに対してはそれぞれ引数を組み立てています。ソースコードは非常にシンプルですが、あえていくつかポイントを挙げると、まずTeX関連のプログラムを実行する時はパスを「\」区切りから「/」区切りに直していることです。これは「System.ini」に「/」で表記すればすむ話ですが、うっかり「\」で設定してエラーになると原因が分かりづらくなるところですので、プログラム内で置換を行っています。

 次に、TeXファイルの出力が成功した時点でその内容をログファイルに書き出している事です。本プログラムは途中でエラーが起きた場合には次ファイルの処理に移るようになっていますが、例えばTeXファイルが正しく出力できた後にエラーが起きたとすると、次の変換パラメタXMLの処理の際にそのTeXファイルは削除されてしまいます。そのような場合でもログファイルにはTeXの内容がテキストとして保存してあるので、エラーの原因を特定したり、またそのまま切り取って新しいテキストファイルに貼り付ければそのまま利用できるかもしれません。最終的に出力されたPDFファイルはドキュメント出力先フォルダ(「DocPath」)に移動しています。

利用方法

 実際には、変換パラメタXMLは外部プログラムから出力することになります。出力書類の分だけ変換パラメタXMLを出力し、バッチ実行プログラムを起動/終了後には変換パラメタXMLを削除するか、別のフォルダに移動します(そのままにしておくと次回バッチ実行プログラムを起動したときに同じ書類が出力されてしまいます)。

 ファイルの書き出しにはDataSetWriteXml()メソッドを利用すると便利です。また、パラメタ値はTeXの文法に沿ったものにする必要があります。改行などがそのまま出力に反映されないなど不便な面もありますが、文字位置を微調整したりグラフィックスを埋め込んだりできます。

最後に

 PDFのバッチ出力といいながらメインは文字列変換ということで、PDFのバイナリを出力するようなイメージを持った方はがっかりされたかもしれません。逆に、PDF出力というとサードパーティー製のモジュールなどを利用しなければならないというイメージを持っている方には、本稿の方法に関心を持っていただけたのではないでしょうか。

 定型書類の出力で求められるのは文字や罫線がレイアウトされた外枠の定位置に文字、画像を埋め込むことぐらいです。これはWordやExcelでも可能ですが、テキストファイルであれば扱いが非常に簡単です。最終出力がPDFなのでAdobe Readerがあれば印刷できます。今後、帳票出力などの方法における選択肢の1つとして参考にしていただければ幸いです。

 なお実は、サンプルのテンプレートは、TeXの文法を全く知らないまま調べながら書いたのでおかしな部分があるかもしれませんが、出力されるPDFファイルに問題がなかったのであえて修正していません。ご了解ください。

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
特集記事連載記事一覧

もっと読む

この記事の著者

(株)オンネット・システムズ 一場 英輔(イチバ エイスケ)

(株)オンネット・システムズについて>業務システム(販売、購買など)の構築をメインに、汎用コンピュータ上で稼動しているシステムのオープン系への移行も行う。要件定義、設計、製造、運用までを一貫して手掛ける。言語はC#、DBはOracleを中心にオブジェクト指向方法論による生産性向上を目指す。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/176 2006/01/19 19:13

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング