はじめに
同僚がデータ修正ツールを作成する上で、修正前のデータと修正後のデータをExcelファイルに出力して表示していた。
社内で使用するだけなら、Office 365がインストールされているPCで行うのでいいのですが、実際に使用してもらうユーザーの環境には場所(工場内など)によってはOfficeがインストールされてないPCがあるため、レビューでExcelファイルをHTMLに変換して表示してもらえるように依頼した。
ExcelファイルからHTML変換
Excelの編集はEPPlusというExcel操作ライブラリーを使用している。
※EPPlus Ver 5系から商用利用は有償となっているため、Ver 4.5系(LGPL ライセンス)を使う。
EPPlusにはHTML変換する機能は備わっていないので、以前ExcelファイルからPDF変換に使用したSpireライブラリーを使用することにした。
Spire.Office
中国のE-iceblue社が提供するofficeの.NETコンポーネントのSpire.Office があり、印刷およびPDF出力やHTML出力をサポートしている。さらに機能制限がある無償版FreeSpire.Officeも提供している。
Spire.officeには、下記コンポーネントが含まれている。個別にダウンロードすることも出来る。
コンポーネント | 内容 | 無償版制限 |
---|---|---|
Spire.Doc | Word ファイルの作成・読み・書き・変換・印刷・エクスポート | Wordファイルの編集は、500段落と25テーブルに制限されています。 \ PDFファイルの変換は最初の3ページのみ。 |
Spire.DocViewer | Word ファイルの表示・変換 | |
Spire.XLS | Excel ファイルの新規作成・編集・変換 | Excelファイルの編集は、ブックごとに5シート、1シートあたり200行に制限されています。 |
Spire.Presentation | PowerPont ファイルの新規作成・編集・変換 | プレゼンテーションスライドが10枚に制限されています。 |
Spire.PDF | PDFドキュメントの作成・読み・書き・編集 | PDFファイルの編集は、10ページに制限されています。 |
Spire.PDFViewer | PDFドキュメントをストリーム、ファイル、バイト配列から読み込み | |
Spire.DataExport | Word/Excel/Access、html、PDF、DBF、SQLスクリプト、csv等の形式にデータをエクスポート | |
Spire.Barcode | バーコードの生成 |
制限の確認
NuGetで「FreeSpire.XLS ver 12.2.0」をインストールする。
FreeSpire.XLSでは、Excelファイルの編集はブックごとに5シート、1シートあたり200行に制限されているのですが、Excelの編集自体はEPPlusを使用するので心配ない。問題はExcelファイルからHTML変換で1シートあたり200行に制限があるかを確認する。
ソースコード
EPPlusで300行のExcelファイルを作成して、FreeSpire.XLSでHTML変換する。
using OfficeOpenXml;
using OfficeOpenXml.Style;
using Spire.Xls;
using System.IO;
using ExcelHorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment;
const int START_ROW = 2;
const int COL_ID = 2;
const int COL_NAME = 3;
const int COL_BIRTHDAY = 4;
private void button1_Click(object sender, EventArgs e)
{
string filePath = @"sample.xlsx";
FileInfo excelFile = new FileInfo(filePath);
if (excelFile.Exists)
{
excelFile.Delete();
excelFile = new FileInfo(filePath);
}
using (var package = new ExcelPackage(excelFile))
{
ExcelWorksheet sheet = package.Workbook.Worksheets.Add("sheet");
// ヘッダーにあたる行を作成
CreateHeaderRow(sheet);
// 300行のデータを作成
Random rnd = new Random();
foreach (var index in Enumerable.Range(1, 300))
CreateRow(sheet, index, rnd);
// 名前と誕生日の幅を広げる
sheet.Column(COL_NAME).Width = 14;
sheet.Column(COL_BIRTHDAY).Width = 16;
//Excelのファイルをセーブする。
package.Save();
}
// HTMLに変換
SaveToHtml(filePath);
MessageBox.Show("完了");
}
// ExcelからHTMLに変換する
private void SaveToHtml(string path)
{
// Spire.XlsでExcelファイルを読み込む
Workbook workbook = new Workbook();
workbook.LoadFromFile(path);
// ExcelからHTMLに変換
Worksheet sheet = workbook.Worksheets[0];
sheet.SaveToHtml("sample.html");
}
// ヘッダー行を作成する
private void CreateHeaderRow(ExcelWorksheet sheet)
{
sheet.Cells[START_ROW, COL_ID].Value = "ID";
sheet.Cells[START_ROW, COL_NAME].Value = "名前";
sheet.Cells[START_ROW, COL_BIRTHDAY].Value = "誕生日";
// ヘッダーセルにスタイルを適用する
var headerCells = sheet.Cells[START_ROW, COL_ID, START_ROW, COL_BIRTHDAY];
// 4方に罫線
headerCells.Style.Border.Top.Style = ExcelBorderStyle.Thin;
headerCells.Style.Border.Left.Style = ExcelBorderStyle.Thin;
headerCells.Style.Border.Bottom.Style = ExcelBorderStyle.Thin;
headerCells.Style.Border.Right.Style = ExcelBorderStyle.Thin;
// 薄いグリーンの背景色で塗りつぶす
headerCells.Style.Fill.PatternType = ExcelFillStyle.Solid;
headerCells.Style.Fill.BackgroundColor.SetColor(Color.LightGreen);
// テキストはセンタリング
headerCells.Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
// 太字
headerCells.Style.Font.Bold = true;
}
// index行目のデータを作る
private void CreateRow(ExcelWorksheet sheet, int index, Random rnd)
{
int row = START_ROW + index;
// id列を作る
sheet.Cells[row, COL_ID].Value = index;
// 名前も適当
sheet.Cells[row, COL_NAME].Value = "鈴木 太郎" + index;
// 誕生日も適当
int year = DateTime.Now.AddYears(-rnd.Next(50)).Year;
int month = rnd.Next(12) + 1;
int day = rnd.Next(28) + 1;
sheet.Cells[row, COL_BIRTHDAY].Value = new DateTime(year, month, day);
// yyyy年mm月dd日形式で誕生日を表示
sheet.Cells[row, COL_BIRTHDAY].Style.Numberformat.Format = "yyyy年mm月dd日";
// 全ての列に4方に罫線のあるスタイルを作って適用する
var cells = sheet.Cells[row, COL_ID, row, COL_BIRTHDAY];
cells.Style.Border.Top.Style = ExcelBorderStyle.Thin;
cells.Style.Border.Left.Style = ExcelBorderStyle.Thin;
cells.Style.Border.Bottom.Style = ExcelBorderStyle.Thin;
cells.Style.Border.Right.Style = ExcelBorderStyle.Thin;
}
出力結果
ExcelファイルからHTML変換で300行表示出来たので、200行の制限については問題なさそうだ。
下記サイトを参考に小計を計算するためにFormulaプロパティに式を使用したものをHTML変換すると例外エラーが発生したので、あくまで簡易なExcelファイルの変換で使用すると割り切った方がいいのかも。
【2022/02/21追記】
例外エラーは「System.NullReferenceException: 'オブジェクト参照がオブジェクト インスタンスに設定されていません。'」で、Formulaを設定しているところをコメントアウトすると例外エラーにならなくなる。
下記のSpire.XLSフォーラムを参考に変換時に数式を計算しないように「workbook.ConverterSetting.IsReCalculateOnConvert = false;」を追加したけど結果は変わらずれ例外エラーのまま。
Export to Pdf Value of =SUM Field is wrong - Forum / Spire.XLS
PDF変換「sheet.SaveToPdf("sample.pdf");」に切り替えるとFormulaを設定した状態でも例外エラーなく、小計も計算されてPDF変換される。
BoostrapのModalで別ページを表示する
BoostrapのModalにて、iframeを使用して別ページを表示する。
- bootstrap modal iframe - programador clic
- Bootstrap 4 のmodalの表示幅を画面いっぱいにするには
- 【JavaScript】ブラウザの高さを取得して要素のheightに設定する
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css">
<style type="text/css">
.modal-dialog-fluid {
max-width: inherit;
width: 98%;
margin-left: 15px;
}
</style>
<script type="text/javascript">
window.addEventListener("load", () => {
let elem = document.getElementById("content");
let wh = window.innerHeight - 250;
elem.style.height = wh + "px";
}, false);
</script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js"></script>
</head>
<body>
<button class="btn btn-primary" data-toggle="modal" data-target="#myModal">Trigger Modal in iFrame</button>
<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-fluid" role="document">
<div class="modal-content">
<div class="modal-header bg-info text-white">
<h4 class="modal-title" id="myModalLabel">動作デモ</h4>
<button type="button" class="close" data-dismiss="modal" aria-hidden="true" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<iframe src="sample.html" width="100%" id="content" frameborder="0" allowtransparency="true"></iframe>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">閉じる</button>
</div>
</div>
</div>
</div>
</body>
</html>
表示結果
テストでは「Trigger Modal in iFrame」ボタンをクリックすると直ぐにModal画面で別ページを表示している。
実際にはクリックしたら抽出条件などをPostAJaxを用いて送信して、ASP.NETのサーバー上でExcelファイルの生成およびHTML変換が完了した段階でModal画面を表示する。
クリック後にModal画面で別ページのsample.html
が表示される。
iFrameのソースを変更したい
Boostrapでモーダルを開く場合、Clickイベントの記述がなくてもクリックするとdata-toggle
とdata-target
の属性指定によりモーダル表示されるようになっています。
iFrameのソースを条件よって変更したい場合、モーダルを開く前に処理を行う必要があります。Boostrapに則った方法を調べるとshow.bs.modal
を使用する方法がありました。
下記の方法でモーダルが開く前にiFrameのソースを変更することが出来ます。
条件によってモーダルを開きたくない場合、return false
でキャンセルすることができます。
$(document).on('show.bs.modal','.modal', function () {
// キャンセルしたい場合、return false;
$("#myModal iframe").attr("src", "sample.html");
})
本当は「$('#myModal').on('show.bs.modal', function ()」のように記載したかったんですが、何故か動かなくて下記参照サイトのようにしたら動きました。
bootstrap jquery show.bs.modal event won't fire
最後に
これでOfficeがインストールされていないPCでも、見た目がExcelのような表示を実現できた。
Officeがインストールされている環境があれば、Excelファイルを開けるボタンを用意するなどすればいいでしょう。
式などあるならHTML変換よりPDF変換の方がいいかも知れない、PDFビューアーすらインストールされていない場合はPDF.js
を使用して表示させる。