Excelの表を「表組するコード」にする際、セルの結合も反映してみる。

昨日は、Excelの表を表組コードに変換する際、併せてセルの色を反映した。
infoment.hatenablog.com

今日は、セルの結合状況も反映することに挑戦する。
f:id:Infoment:20181014203330p:plain

今日やりたいこと

Excelで作成した表から、「はてなブログ」用に表組するコードを作成する際に、セルの結合状況を反映したい。

必要なこと

  1. HTMLコードで作成する表について、セルの結合方法を確認
  2. 表のデータ範囲において、セルの結合状況(情報)を得る
  3. 得た情報を元に、作成済みクラスモジュールを改修する

1.HTMLコードで作成する表について、セルの結合方法を確認

これはもう、考えてみても解らない。
調べたところ、Resizeの感覚で行うことが分かった。

  • 行方向で結合する場合:<td rowspan=n> ※n行結合する
  • 列方向で結合する場合:<td rowspan=n> ※n列結合する

2.表のデータ範囲において、セルの結合状況(情報)を得る

セルが結合されているかどうかは、MergeCellsプロパティで確認できる。
対象セル.MergeCells が True なら結合されている。False なら結合されていない。
そこで、次のように考えた。

  1. セルが結合されているか否かを確認する。
  2. 結合されていなければ、そのまま表組コードを作成する。
  3. 結合されていて、且つ、結合されたセルの一番左上のセルの場合、結合されたサイズに拡張して表組する。
  4. 結合されていて、且つ、結合されたセルの一番左上のセルではない場合、何もしない。

3.得た情報を元に、作成済みクラスモジュールを改修する

以上の情報を整理して、クラスモジュールを改修した。

【クラスモジュール】(HTMLTableClass)

結合状況を確認する関数を作成。
【戻り値】
0・・・結合されていないセル
1・・・結合された範囲の一番左上のセル
2・・・結合された範囲の一番左上以外のセル

Private Function GetMergeIndex(r As Range) As Long
    If r.MergeCells Then
        If r.MergeArea.Item(1).Address = r.Address Then
            GetMergeIndex = 1
        Else
            GetMergeIndex = 2
        End If
    Else
        GetMergeIndex = 0
    End If
End Function

ボディ部のデータを作成するサブプロシージャを改修。
結合されたセルであって、且つ一番左上でない場合は、表組コードを作成しない。
また今回、関数TDの引数として表の行数を追加し、ヘッダー部のコードもまとめて作成することにした。

Private Sub TableBodyData()
    Dim i As Long
    Dim r As Range
        For i = 1 To TableRange.Rows.Count
            col.Add vbTab & "<tr>"
            For Each r In TableRange.Rows(i).Cells
                If GetMergeIndex(r) <> 2 Then
                    col.Add vbTab & vbTab & TD(r, i)
                End If
            Next
            col.Add vbTab & "</tr>"
        Next
End Sub

結合する行数を取得。

Private Property Get RowSpan(r As Range) As Long
    If r.MergeCells Then
        RowSpan = r.MergeArea.Rows.Count
    Else
        RowSpan = 1
    End If
End Property

結合する列数を取得。

Private Property Get ColSpan(r As Range) As Long
    If r.MergeCells Then
        ColSpan = r.MergeArea.Columns.Count
    Else
        ColSpan = 1
    End If
End Property

ボディ部のデータ作成。

Private Property Get TD(r As Range, row_number) As String
    Dim myResize As String
        If GetMergeIndex(r) = 1 Then
            myResize = " rowspan=" & RowSpan(r) & " colspan=" & ColSpan(r)
        Else
            myResize = ""
        End If

    Dim myAlignment As String
        myAlignment = " align="

        Select Case r.HorizontalAlignment
            Case xlLeft
                myAlignment = myAlignment & """left"""
            Case xlCenter
                myAlignment = myAlignment & """center"""
            Case xlRight
                myAlignment = myAlignment & """right"""
            Case Else
                myAlignment = ""
        End Select
    
    Dim HCC As New HTMLColorClass
        HCC.DexNumber = r.Interior.Color
    
    Dim myColor As String
        myColor = " bgcolor=" & HCC.HTMLColor
        
        Select Case row_number
            Case 1
                TD = "<th" & myResize & " align=""center"">" & r & "</th>"
            Case Else
                TD = "<td" & myResize & myAlignment & myColor & ">" & r.Value & "</td>"
        End Select
End Property

結果

セルの結合状況を、表に反映させることが出来た。
f:id:Infoment:20181014220034p:plain

品名 産地 値段(単価) 評判
りんご 青森県 100 超美味しい
みかん 熊本県 200 極美味しい
ばなな フィリピン 300 超美味しい
ブロッコリー 埼玉県 150
里芋 200 極美味しい
その他の野菜 50 とにかく美味しい

コードはこちら。手入力?ちょっとシンドイ。

<table>
	<tr>
		<th align="center">品名</th>
		<th align="center">産地</th>
		<th align="center">値段(単価)</th>
		<th rowspan=1 colspan=2 align="center">評判</th>
	</tr>
	<tr>
		<td bgcolor=#C00000>りんご</td>
		<td bgcolor=#FFFFFF>青森県</td>
		<td align="left" bgcolor=#FFFFFF>100</td>
		<td bgcolor=#FFFFFF>超美味しい</td>
		<td bgcolor=#FFFFFF></td>
	</tr>
	<tr>
		<td align="left" bgcolor=#FFFFFF>みかん</td>
		<td align="left" bgcolor=#FFFFFF>熊本県</td>
		<td align="center" bgcolor=#70AD47>200</td>
		<td bgcolor=#FFFFFF></td>
		<td bgcolor=#FFFFFF>極美味しい</td>
	</tr>
	<tr>
		<td align="left" bgcolor=#FFFFFF>ばなな</td>
		<td align="left" bgcolor=#FFFFFF>フィリピン</td>
		<td align="right" bgcolor=#FFFFFF>300</td>
		<td rowspan=2 colspan=1 align="left" bgcolor=#FFFFFF>超美味しい</td>
		<td bgcolor=#FFFFFF></td>
	</tr>
	<tr>
		<td align="left" bgcolor=#FFC000>ブロッコリー</td>
		<td rowspan=2 colspan=1 align="left" bgcolor=#FFFFFF>埼玉県</td>
		<td bgcolor=#FFFFFF>150</td>
		<td bgcolor=#FFFFFF></td>
	</tr>
	<tr>
		<td align="left" bgcolor=#FFFFFF>里芋</td>
		<td align="right" bgcolor=#FFFFFF>200</td>
		<td bgcolor=#FFFFFF></td>
		<td bgcolor=#FFFFFF>極美味しい</td>
	</tr>
	<tr>
		<td rowspan=1 colspan=2 align="center" bgcolor=#FFFFFF>その他の野菜</td>
		<td align="right" bgcolor=#FFFFFF>50</td>
		<td rowspan=1 colspan=2 align="center" bgcolor=#FFFFFF>とにかく美味しい</td>
	</tr>
</table>

ただし、このマクロには、現時点で一つ欠陥があることが分かっている。それは、ヘッダー行が複数行で構成されている場合に対応できていない点だ。そこは、追々改修するとしよう。

参考まで。