前回はセルが結合している場合、うまく変換することができませんでした。今回は変換できるようにします。
実行結果はこんな感じになります。
場所 | 住所 | 最寄り駅 | 最寄り駅情報 | 徒歩 |
---|---|---|---|---|
国会議事堂 | 東京都千代田区永田町1-7-1 | 国会議事堂前駅 | 東京メトロ丸ノ内線/東京メトロ千代田線 | 徒歩 4分 |
永田町駅 | 東京メトロ南北線/東京メトロ半蔵門線/東京メトロ有楽町線 | 徒歩 4分 | ||
溜池山王駅 | 東京メトロ銀座線/東京メトロ南北線 | 徒歩 9分 | ||
東京都庁 | 東京都新宿区西新宿二丁目 | 都庁前駅 | 都営大江戸線 | 徒歩 2分 |
西新宿駅 | 東京メトロ丸ノ内線 | 徒歩 6分 | ||
新宿駅 | JR在来線/京王新線/京王線/小田急小田原線/都営新宿線/都営大江戸線 | 徒歩 6分 | ||
国会図書館 | 東京都千代田区永田町1丁目10-1 | 永田町駅 | 東京メトロ南北線/東京メトロ半蔵門線/東京メトロ有楽町線 | 徒歩 3分 |
国会議事堂前駅 | 東京メトロ丸ノ内線/東京メトロ千代田線 | 徒歩 8分 | ||
半蔵門駅 | 東京メトロ半蔵門線 | 徒歩 9分 |
1 |
var mergedRanges = worksheet.MergedRanges; |
とやればマージされている(ほかのセルと結合されている)セルを取得できます。また
1 2 |
IXLCell firstCell = mergedRange.FirstCell(); IXLCell lastCell = mergedRange.LastCell(); |
このようにすれば結合されているセルの最初のものと最後のものを取得できます。
1 2 |
int rowSpan = lastCell.Address.RowNumber - firstCell.Address.RowNumber + 1; int columSpan = lastCell.Address.ColumnNumber - firstCell.Address.ColumnNumber + 1; |
これで何列(何行)つながっているかもわかります。2以上であればつながっていることになります。
ボタンがクリックされたときのイベントハンドラは同じです。GetHtmlFromExcel(string excelPath)メソッドではGetTableHeaderメソッドとGetTableDataメソッドを呼び出していましたが、各メソッドが長くなるのでひとつにまとめました(後述)。それから最大幅を指定できるようにしました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
public partial class Form1 : Form { private void button1_Click(object sender, EventArgs e) { OpenFileDialog dialog = new OpenFileDialog(); dialog.Filter = "Excelファイル(*.xlsx)|*.xlsx"; if (dialog.ShowDialog() == DialogResult.OK) { richTextBox1.Text = GetHtmlFromExcel(dialog.FileName); } dialog.Dispose(); } string GetHtmlFromExcel(string excelPath) { string str = ""; using (var workbook = new XLWorkbook(excelPath)) { string ruledlineColorCode = GetColorCode(this.RuledlineColor); string ruledlineWidth = this.RuledlineWidth.ToString(); IXLWorksheet worksheet = workbook.Worksheet(1); // div タグをつけて最大幅を指定できるようにする str += String.Format("<div style=\"width:100%; max-width:{0}px;\">", (int)numericUpDown1.Value); str += String.Format("<table border=\"{0}\" width=\"100%\" cellspacing=\"0\" cellpadding=\"5\" bordercolor=\"{1}\">\n", ruledlineWidth, ruledlineColorCode); int rowCount = GetRowCount(worksheet); int columCount = GetColumCount(worksheet); str += GetTableData(worksheet, rowCount, columCount); str += "</table>\n"; str += "</div>\n"; } return str; } } |
セルの場所を保存するためのクラスを作成しました。RowSpanとColumSpanはどれだけつながっているかを記録します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
public class Cell { public Cell(int row, int colum) { Row = row; Colum = colum; } public Cell(int row, int colum, int rowCount, int columCount) { Row = row; Colum = colum; RowSpan = rowCount; ColumSpan = columCount; } public int Row = 0; public int Colum = 0; public int RowSpan = 0; public int ColumSpan = 0; } |
以下はrowとcolumから文字色のカラーコードを取得するためのメソッドです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
public partial class Form1 : Form { string GetForeColorCode(int row, int colum) { if (row == 1) return GetColorCode(this.FirstRowForeColor); else { if (colum == 1) return GetColorCode(this.FirstColumForeColor); else return GetColorCode(this.OtherForeColor); } } string GetBackColorCode(int row, int colum) { if (row == 1) return GetColorCode(this.FirstRowBackColor); else { if (colum == 1) return GetColorCode(this.FirstColumBackColor); else return GetColorCode(this.OtherBackColor); } } string GetColorCode(Color color) { return String.Format("#{0}{1}{2}", ((int)color.R).ToString("x2"), ((int)color.G).ToString("x2"), ((int)color.B).ToString("x2")); } } |
全部でどれだけ行と列があるのかを調べるGetRowCountメソッドとGetColumCountメソッドを変更しました。もし結合しているセルをみつけたら次に探す値を変更しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
public partial class Form1 : Form { int GetRowCount(IXLWorksheet worksheet) { int i = 1; while (true) { IXLCell cell = worksheet.Cell(i, 1); string str = cell.GetValue<string>(); if (str == null || str == "") break; if (cell.IsMerged()) { IXLRange mergedRange = cell.MergedRange(); i = mergedRange.LastCell().Address.RowNumber; } i++; } return i - 1; } int GetColumCount(IXLWorksheet worksheet) { int i = 1; while (true) { IXLCell cell = worksheet.Cell(1, i); string str = cell.GetValue<string>(); if (str == null || str == "") break; if (cell.IsMerged()) { IXLRange mergedRange = cell.MergedRange(); i = mergedRange.LastCell().Address.ColumnNumber; } i++; } return i - 1; } } |
GetMergedCellsメソッドは他のセルに結合されているセルと最初のセルのリストを取得するメソッドです。最初のセルを求めたら上記の方法でどれだけセルがつながっているかも調べてリストに格納します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
public partial class Form1 : Form { void GetMergedCells(IXLWorksheet worksheet, out List<Cell> mergedCells, out List<Cell> mergedFirstCells) { mergedCells = new List<Cell>(); mergedFirstCells = new List<Cell>(); var mergedRanges = worksheet.MergedRanges; foreach (var mergedRange in mergedRanges) { IXLCell firstCell = mergedRange.FirstCell(); IXLCell lastCell = mergedRange.LastCell(); mergedFirstCells.Add( new Cell( firstCell.Address.RowNumber, firstCell.Address.ColumnNumber, lastCell.Address.RowNumber - firstCell.Address.RowNumber + 1, lastCell.Address.ColumnNumber - firstCell.Address.ColumnNumber + 1) // セルの場所だけでなくどれだけつながっているかも調べる ); var cells = mergedRange.Cells(); foreach (var cell in cells) { int colum = cell.Address.ColumnNumber; int row = cell.Address.RowNumber; if (!mergedFirstCells.Any(x => x.Row == row && x.Colum == colum)) mergedCells.Add(new Cell(row, colum)); // 結合している最初のセルはmergedFirstCellsに格納して // mergedCellsには格納しない } } } } |
GetTableDataメソッドでtableタグの本体を取得します。結合しているセルに関する情報を集めて、結合しているセルの最初のセルであるなら colspan、colspanなどの適切なタグをいれます。それ以外の結合しているセルは無視します。これでtableタグが取得できるはずです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
public partial class Form1 : Form { string GetTableData(IXLWorksheet worksheet, int rowCount, int colomCount) { List<Cell> mergedCells = new List<Cell>(); List<Cell> mergedFirstCells = new List<Cell>(); // 結合しているセルに関する情報を取得する(前述) GetMergedCells(worksheet, out mergedCells, out mergedFirstCells); var mergedRanges = worksheet.MergedRanges; string ret = ""; for(int row = 1; row<= rowCount; row++) { ret += "<tr>\n"; for (int colum = 1; colum <= colomCount; colum++) { var cell = worksheet.Cell(row, colum); string str = cell.GetValue<string>(); if (mergedCells.Any(x => x.Row == row && x.Colum == colum)) continue; string frontColorCode = GetForeColorCode(row, colum); string backColorCode = GetBackColorCode(row, colum); var first = mergedFirstCells.FirstOrDefault(x => x.Row == row && x.Colum == colum); if (row == 1) ret += String.Format("<th style =\"color: {0}; background-color:{1}\"", frontColorCode, backColorCode); else ret += String.Format("<td style =\"color: {0}; background-color:{1}\"", frontColorCode, backColorCode); // 結合しているセルの最初のセルであるなら適切なタグをいれる if (first != null) { int rowSpan = first.RowSpan; int columSpan = first.ColumSpan; if (rowSpan >= 2 && columSpan >= 2) ret += String.Format(" rowspan=\"{0}\" colspan=\"{1}\">", rowSpan, columSpan); else if (rowSpan >= 2) ret += String.Format(" rowspan=\"{0}\">", rowSpan); else if (columSpan >= 2) ret += String.Format(" colspan=\"{0}\">", columSpan); } else ret += String.Format(">", frontColorCode, backColorCode); if (row == 1) ret += String.Format("{0}</th>\n", str); else ret += String.Format("{0}</td>\n", str); } ret += "</tr>\n"; } return ret; } } |
これが生成されたtableタグです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
<div style="width:100%; max-width:500px;"><table border="1" width="100%" cellspacing="0" cellpadding="5" bordercolor="#000000"> <tr> <th style ="color: #ffffff; background-color:#000000">場所</th> <th style ="color: #ffffff; background-color:#000000">住所</th> <th style ="color: #ffffff; background-color:#000000">最寄り駅</th> <th style ="color: #ffffff; background-color:#000000">最寄り駅情報</th> <th style ="color: #ffffff; background-color:#000000">徒歩</th> </tr> <tr> <td style ="color: #000000; background-color:#ffff00" rowspan="3">国会議事堂</td> <td style ="color: #000000; background-color:#ffffff" rowspan="3">東京都千代田区永田町1-7-1</td> <td style ="color: #000000; background-color:#ffffff">国会議事堂前駅</td> <td style ="color: #000000; background-color:#ffffff">東京メトロ丸ノ内線/東京メトロ千代田線</td> <td style ="color: #000000; background-color:#ffffff">徒歩 4分</td> </tr> <tr> <td style ="color: #000000; background-color:#ffffff">永田町駅</td> <td style ="color: #000000; background-color:#ffffff">東京メトロ南北線/東京メトロ半蔵門線/東京メトロ有楽町線</td> <td style ="color: #000000; background-color:#ffffff">徒歩 4分</td> </tr> <tr> <td style ="color: #000000; background-color:#ffffff">溜池山王駅</td> <td style ="color: #000000; background-color:#ffffff">東京メトロ銀座線/東京メトロ南北線</td> <td style ="color: #000000; background-color:#ffffff">徒歩 9分</td> </tr> <tr> <td style ="color: #000000; background-color:#ffff00" rowspan="3">東京都庁</td> <td style ="color: #000000; background-color:#ffffff" rowspan="3">東京都新宿区西新宿二丁目</td> <td style ="color: #000000; background-color:#ffffff">都庁前駅</td> <td style ="color: #000000; background-color:#ffffff">都営大江戸線</td> <td style ="color: #000000; background-color:#ffffff">徒歩 2分</td> </tr> <tr> <td style ="color: #000000; background-color:#ffffff">西新宿駅</td> <td style ="color: #000000; background-color:#ffffff">東京メトロ丸ノ内線</td> <td style ="color: #000000; background-color:#ffffff">徒歩 6分</td> </tr> <tr> <td style ="color: #000000; background-color:#ffffff">新宿駅</td> <td style ="color: #000000; background-color:#ffffff">JR在来線/京王新線/京王線/小田急小田原線/都営新宿線/都営大江戸線</td> <td style ="color: #000000; background-color:#ffffff">徒歩 6分</td> </tr> <tr> <td style ="color: #000000; background-color:#ffff00" rowspan="3">国会図書館</td> <td style ="color: #000000; background-color:#ffffff" rowspan="3">東京都千代田区永田町1丁目10-1</td> <td style ="color: #000000; background-color:#ffffff">永田町駅</td> <td style ="color: #000000; background-color:#ffffff">東京メトロ南北線/東京メトロ半蔵門線/東京メトロ有楽町線</td> <td style ="color: #000000; background-color:#ffffff">徒歩 3分</td> </tr> <tr> <td style ="color: #000000; background-color:#ffffff">国会議事堂前駅</td> <td style ="color: #000000; background-color:#ffffff">東京メトロ丸ノ内線/東京メトロ千代田線</td> <td style ="color: #000000; background-color:#ffffff">徒歩 8分</td> </tr> <tr> <td style ="color: #000000; background-color:#ffffff">半蔵門駅</td> <td style ="color: #000000; background-color:#ffffff">東京メトロ半蔵門線</td> <td style ="color: #000000; background-color:#ffffff">徒歩 9分</td> </tr> </table> </div> |