見出し画像

テンプレートを使ったexcelファイル出力方法(C#)-1.設計

この間excelファイルの出力機能を実装したので記事を書くことにしました。

今回は下記のような順で解説していきます。

前書き

プログラミングする場合、excelファイルを出力する機能はよくあるニーズでしょう。

excelファイルの出力機能を備えば、大量のデータをexcelファイルに出力することができるようになります。後で、ユーザがOffice Excelアプリで開くことができるので参照、編集にも便利になりますね。

そして、データ一括入力の一環として事前にフォーマット(仕様)付きのexcelファイルを出力すると、システムに登録したいデータをそのexcelファイルに書き込み、後でシステムに読み込ませることができるので、大量データの登録作業も楽になるでしょう(データを1件ずつ入力するよりは)。

データの出力、入力には一番簡単なCSVファイルを使うのもよくありますが、ケース・バイ・ケースでしょう。CSVファイルは単なるカンマ(かタブかスペース)区切りのテキストファイルにすぎないので、確かに(excelファイルよりは)人間が見ずらい点があります。

単純に前のシステムでデータ出力し、次のシステムで読み込むだけだったら、軽量なCSVファイルでやり取りすることをお勧めします(人間が見る必要のない場合)。

出力したデータを、後で人間が参照したり、編集したりする必要がある場合は、excelファイルが一番向いてるでしょう。

今回はC#でexcelファイルを出力する方法について解説していきます。

プログラミングの考え方は基本同じなので、javaでも同じ方法で実現することができます。

そして、今回は考え方やプログラム設計からC#のソースまで解説していく予定なので、長くなったら幾つかの記事に分けて書きます。

本記事ではソフトウェア開発における概要設計詳細設計(のプログラム設計)、実装といった内容の順に解説していきます。実際のIT企業でも、このような感じでアプリを設計、製造、(テスト)していくものです。

■本記事の想定読者
 ・C#プログラミング基礎のある方
  但し、設計部分はプログラミング言語と関係ないので全員向けになります。

ニーズ(要求・要望)の提出

■「データをexcelファイルに出力する機能を開発したい。」
■ただ、単なるデータを出力するだけではなく、「excelファイルのフォーマット(見た目)を事前に定義できるようにしたい。」
■「後でexcelファイルのフォーマット(見た目)を変更すれば、ソース修正無しにデータ出力も最新フォーマットに準拠するようにしたい。」

今回実現したい機能は上記の通りです。つまり何のことかというと、
作成するexcelファイルのデータの部分と、フォーマット(見た目)の部分分離することがポイントですね。

実は、ここで言ってるフォーマット(見た目)部分の定義もexcelファイルで行うのが普通で、「テンプレート」とも呼びます。

これからは、便宜上フォーマット(見た目)の代わりに「テンプレート」という文言を使います。

上記の要求を図でいうと、下記のようなテンプレートファイルを作成し、

画像1

実際にデータを表示したいセルに「${header.date}」、「${header.title}」、「${footer.thisAmount}」のような感じで定義を行い

プログラム内で定義したセルにそれぞれの値を出力すれば実現できることになります。

こうすることで、テンプレートで文字のフォントとかサイズとかセルの背景色、罫線などの定義が可能になります。見た目の定義は全て結果ファイルに引き継がれます。

このようなテンプレートを使い、実際にデータを出力した結果は下記のような感じです。

画像2

既に気になったかもしれませんが、テンプレートにはセルの定義方法が2種類ありますね。

1つは「${header.title}」のような定義方法(「normal項目」と呼ぶことにします)と、もう1つは「$LIST[].custName」、「$LIST[].itmName」のような定義方法(「list項目」と呼ぶことにします)です。

できるだけ共通機能として開発し、将来他のプログラムでも使えるようにするために、「normal項目」と「list項目」をサポートするようにしました。

この2種類の項目をサポートすれば、基本的にどんなexcelファイルも作成できます
「list項目」ではなく、「normal項目」だけでも実現できないわけではないですが、全て「normal項目」だと、きっと「1ページに出すのはn行まで」とか、「max行分データがなくても、統計部分は1ページの一番下に表示」等々、いろいろ制限が付くはずですね。

このような制限をなくすために、実際のデータの行数に合わせて動的にexcelファイル内のリスト項目の行数を増やす機能が必要になります。これが「list項目」です。
アプリを開発する時、お客さんのニーズ(今回は筆者自分で要望を考え、自分でプログラミングしてますけど)だけを考え、それだけを実現するというのは確かに要件には満たしたものの、あんまりお勧めできません。

設計段階で将来の移植性とか拡張性にも十分注意する必要があります。
そうじゃないと、もしお客さんの要望が変わった場合には速やかな対応ができず、進捗などに影響を及ぼすことになります。

でも、又、将来の拡張性とかについて考えすぎると、現段階の設計、製造が滞す原因にもなりかねないので、このへんはバランスよく調整したほうがよさそうです。(ケース・バイ・ケース思考で、現場の雰囲気把握が一番重要になるでしょう。)

今回実現したい要望からの仕様の纏めは、こんな感じです。
これでやりたいことが決まりました。

後、最後に考えておくべきポイントは、「list項目」の導入により、下記の問題が発生するので、よく考えて設計する必要があります。

画像3

■テンプレートでは、「list項目」の定義は1行のみだが、実際のデータファイルでは複数行になるので、list項目の次に定義した全ての項目(e.g.統計値部分等)の行番号がテンプレートと実際のデータファイルと一致しない場合があります。
(テンプレート解析し、行番号を覚えてデータを設定する時は要注意)
※もちろん、こんな問題は詳細設計段階で考慮すべきことだが、上記のような要望に応じて「list項目をサポートしよう」と決めた時点で、こんな問題があるようね。。。とすぐ連想できるのも、設計者のスキルになるでしょう。

概要設計

プログラム要望と、大まかな考え方ができた後は、プログラムの設計段階に入ります。

いきなり詳しく考えようとはしないで、先ずは「大まかなレベル」でいいので、「要望をどのような処理流れで実現したいか」に焦点を置きます。これが概要設計です。

今回のニーズを実現するためには、「テンプレートを先に作成し」、プログラムではきっと「このテンプレートを解析し(A)」、テンプレートで「定義したセルに、実際のデータを書き込む(B)」というような処理が必要になるでしょう。

上記のような処理をうまく設計し、実装すれば実現できるはずですね。

こうして、おおざっぱに(A)と(B)といった、2つの処理を実現する必要があることが分かりました。

次に概要設計段階で、大まかの処理の流れ図を作成してみます。(筆者はよく「処理流れ概念図」と呼びますが、権威ではないので、あくまでも自分だけの呼び方です)

■処理流れ概念図

0000-処理流れ概念図

このように図を描けておけば、自分の考え方を相手に説明する時にも便利になります。

概要設計段階では、「とりあえずこうすれば実現できる」という処理の流れを考えることがポイントです。

概要設計段階では、あんまり詳しく考えない方がいいですね。そうじゃないと、その処理だけを考えすぎて、全体図の把握が難しくなります。

(↑の図でいうと、本当に必要な機能だけを繋げて処理の全体を表しています。)

もちろん、「あんまり詳しく考えない」といって、又、誰が見ても明らかに間違ってる(実現不可能)処理になるのも望ましくないでしょう。

筆者が設計したのは、↑図のように、
①.(テンプレートは後でも又使うので)テンプレートをコピーし、
②.①でコピーしたテンプレートをプログラムに読み込ませ、
 処理Aでテンプレートを解析し、
 処理Bでテンプレート解析結果と、実際のデータを受け取り、
 定義したセルに実際の値を設定し、
③.結果excelファイルにデータを書き込む
といった処理の流れでした。

詳細設計(プログラム設計)

処理概要ができたら、次は詳細設計段階に入ります。

詳細設計では、それぞれの機能(モジュールとも呼びます)に対し、処理内容を詳しく展開していきます。

詳細設計を書いたドキュメントが「詳細設計書」です。詳細設計書はwordファイルなのかexcelファイルなのかは会社によって違います。

そして、実は「詳細設計」と「プログラム設計」は違うものになります。
詳細設計は、単なる処理機能を詳しく展開し、wordかexcelファイルに書けばよいですが、
プログラム設計には「Judo」とか「Terasoluna」等ちゃんと設計ツールがあります。プログラム設計でよく使うのは「UML」のような統一モデリング言語というものです。

ただ、「詳細設計」と「プログラム設計」を分けると、それなりに開発費用が掛かっちゃうので、詳細設計だけ行って、プログラム設計はプログラマーに任せるのが普通です。

詳細設計を書くと記事がすごく長くなるので、本記事では詳細設計に関しては割愛します。

次は、プログラム設計に関して解説していきます。この段階から初めて「どのプログラミング言語を使うのか?」の問題を考慮する必要があります。

実際に開発するプログラムを設計することになるので、先に使用するプログラミング言語を決める必要があります。プログラミング言語によって設計が違ってきます。

例えば、「C言語」を使う場合、(C言語にはクラスという概念がないので)全てがグルーバル変数、構造体、関数とローカル変数、構造体、関数などの設計になるでしょう。

そして、C#とかJavaを使う場合、全てのメソッドは必ずクラスに所属する必要があるので、クラスの設計、メンバ変数、メソッドなどの設計になるでしょう。

このように、実際に使うプログラミング言語の特徴、出来ることできないこと等によって、プログラミング設計書もそれぞれ違う形になります。

本記事ではC#を使って開発するので、C#での実現方法に特化したプログラム設計を行います。

実際の開発では、あんまりプログラム設計は要求してないのが普通です。ただ、実装前にプログラム設計をしておけば、問題の早期発見もできるし、実装全般のイメージが掴みやすいので、時間の許す限り作成してみることをお勧めします。

今回の開発では、下記のようなツール、ライブラリを使います。

□プログラミング言語: C# ( .NET Framework 4.5)
□開発用IDE: Microsoft Visual Studio 2019 Community
□excelファイル操作用ライブラリ: NPOI 2.3
※NPOIの使い方、インストール方法に関してはインターネットを検索してください。

そして、下記のようにクラス分けをしています。

■クラス図(概要)

0000-クラス図概念

CTemplatedExcelData
  excelファイルに出力するデータを保持するクラス。
CTemplatedExcelUtil
  主にテンプレートファイルの解析処理と結果excelファイルの出力処理を提供するクラス。

大まかには上記の2つのクラスでお客さんの要望を実現します。なお、シーケンス図は下記の通りです。

■シーケンス図(概要)

0000-seq概念

出力したいデータをCTemplatedExcelDataクラスに保持し、CTemplatedExcelUtilクラスの「excelファイル作成()」メソッドを呼び出します。

これで、今回開発する機能の処理イメージ(メイン流れ)はできました。

後は、上記の「骨組み」の感じのクラス図、シーケンス図に必要に応じて「肉」を付ける処理を行います。

そして、最後にできたクラス図(全クラス網羅)は下記の通りです。

■クラス図(全体)

画像7

実際の開発に必要であろうクラスと各メソッドを全て記載しています。

そして詳しいシーケンス図は下記の通りです。

■シーケンス図(全体)

画像8

説明:
1/2/3:ここではexcelに出力したいデータをCTemplatedExcelDataクラスインスタンスにどんどん追加しています。

4/5:CTemplatedExcelUtilクラスインスタンスを作成し、メソッドCreateExcel()を呼び出しています。

5.3:analysisTemplatedExcel()メソッド内でテンプレートファイルの解析処理を行います。解析結果はクラス「CTemplatedExcel」に保持しておきます。

5.4:setValueBasedTemplatedExcel()メソッド内で、テンプレート解析結果に応じてそれぞれのセル内にデータを書き込んでいきます。

5.4.1/5.4.2:テンプレートファイルに、複数のシートが存在する場合、シート数分繰り返しながらデータを設定している処理になります。ここで、本機能はマルチシートをサポートすることがわかるでしょう。

5.4.3.x/5.4.4.x:excelファイルにデータを出力する処理は、基本的に行数分、行の中では列の数分くり返しながら、それぞれのセルにデータを設定していることが分かるでしょう。

5.5/5.6:NPOIライブラリによって提供されるインタフェース「IWorkbook」のWrite()メソッドとClose()メソッドを使って結果excelファイルを作成しています。

まとめ

これで、「テンプレートを使ってexcelファイルを作成する」プログラムの設計が完了しました。

作成すべきクラスと各クラス内のメンバー変数、メンバー関数(メソッド)は上記のクラス図に記載してる通りになります。

そして、各クラスの呼び出しの流れは上記シーケンスの通りです。

この記事では、実際にプログラムを作成する前の設計段階で考えること、作成するドキュメント等についておおざっぱに解説しました。

次回は、上記クラス図に書いてあるクラスを1個ずつプログラミングしていきます。

では、バイバイ! Have a nice day!

この記事が気に入ったらサポートをしてみませんか?