【上級者向け】Wordの「段落」書式設定をJSONで外部管理し、設定変更を容易にする – 疎結合設計とレガシーシステム保守の極意
長年、Word VBAの世界に身を置き、数々の自動化プロジェクトの最前線で戦ってきた者として、貴殿らの熱意は痛いほど理解できる。日々、業務効率化という名の聖杯を追い求め、VBAという古くて新しい武器を手に、複雑怪奇なWord文書に立ち向かっていることだろう。
しかし、ふと立ち止まってみれば、我々が日々書き綴るVBAコードは、しばしば「ハードコーディング」という名の呪縛に囚われていることに気づくはずだ。特に、段落のフォント、行間、インデントといった書式設定は、コード内に直接記述されることが常だ。これは、一見すると手っ取り早いように見えるが、設定変更が発生するたびにコードを追記・修正し、場合によっては文書全体に影響を及ぼすリスクを孕む。レガシーシステムを保守する者ならば、その痛みを骨身にしみて感じているはずだ。
本稿では、この「ハードコーディング」の呪縛から解放され、JSONファイルを用いて段落の書式設定を外部管理するという、より疎結合で保守性の高い設計思想について深掘りしていく。これは単なる小手先のテクニックではなく、システム全体のアーキテクチャレベルでの改善、さらにはWindows APIの知見やメモリ最適化といった、熟練エンジニアのみが到達できる領域に踏み込むものだ。
なぜJSONなのか? – データとロジックの分離という鉄則
まず、なぜJSONなのか。その理由は、「データとロジックの分離」という、システム設計における普遍的な鉄則に合致するからだ。
- 可読性と汎用性: JSONは人間が読みやすく、かつ機械が解析しやすい構造を持つ。様々なプログラミング言語で標準的にサポートされており、将来的なシステム連携においても強力なアドバンテージとなる。
- 構造化されたデータ表現: 段落の書式設定は、フォント名、サイズ、太字、斜体、行間、インデントといった複数の属性で構成される。JSONであれば、これらを階層的に、かつ明確に定義できる。
- 設定変更の容易さ: 書式設定の変更は、VBAコードを一切変更することなく、JSONファイルを編集するだけで完結する。これは、非エンジニアの担当者でも容易に設定変更を行えることを意味し、開発・運用コストを劇的に削減する。
疎結合設計がもたらす恩恵 – オブジェクトのライフサイクルとパフォーマンス
JSONによる外部管理は、VBAコードと書式設定データを完全に分離する。これにより、VBAコードは「書式設定を適用するロジック」に特化し、書式設定データは「設定内容の定義」に特化する。この分離は、以下のような恩恵をもたらす。
- コードの簡潔化と可読性の向上: VBAコードは、JSONを読み込み、パースし、Wordの段落オブジェクトに適用するという一連の処理に集中できる。これにより、コードが簡潔になり、意図が明確になる。
- 保守性の向上: 書式設定の変更がJSONファイルのみに影響するため、VBAコードへの影響を心配する必要がない。レガシー環境の保守においては、この「影響範囲の限定」がどれほど重要か、貴殿らなら理解できるはずだ。
- パフォーマンスへの配慮 – オブジェクトの明示的解放: VBAにおいて、オブジェクトの生成と破棄はパフォーマンスに直結する。特に、多数の段落やフォントオブジェクトを扱う場合、メモリリークや不要なリソース消費は避けたい。JSONから読み込んだ設定を適用する際、一時的に生成されるオブジェクトは、処理の完了後に`Set obj = Nothing`を用いて明示的に解放することが極めて重要である。これにより、Wordアプリケーション全体の応答性を維持し、予期せぬクラッシュを防ぐ。これは、Windows APIを直接呼び出すような低レベルの操作を行う際に、さらにその重要性が増す。
JSON構造の設計 – 汎用性と拡張性を意識して
まず、JSONファイルの構造を定義する。ここでは、文書全体で共通して利用される書式設定のテンプレートを定義する例を示す。
{
“paragraphStyles”: [
{
“name”: “Heading1”,
“font”: {
“name”: “メイリオ”,
“size”: 16,
“bold”: true,
“italic”: false,
“color”: “000000” // RGB形式 (Hex)
},
“paragraphFormat”: {
“lineSpacing”: 1.5, // 倍数
“spaceBefore”: 12, // ポイント
“spaceAfter”: 6, // ポイント
“leftIndent”: 0, // ポイント
“firstLineIndent”: 0 // ポイント
}
},
{
“name”: “Normal”,
“font”: {
“name”: “游ゴシック”,
“size”: 10.5,
“bold”: false,
“italic”: false,
“color”: “333333”
},
“paragraphFormat”: {
“lineSpacing”: 1.2,
“spaceBefore”: 0,
“spaceAfter”: 0,
“leftIndent”: 0,
“firstLineIndent”: 0
}
},
{
“name”: “IndentedText”,
“font”: {
“name”: “メイリオ”,
“size”: 10,
“bold”: false,
“italic”: false,
“color”: “000000”
},
“paragraphFormat”: {
“lineSpacing”: 1.5,
“spaceBefore”: 3,
“spaceAfter”: 3,
“leftIndent”: 18, // 18ポイントのインデント
“firstLineIndent”: 0
}
}
// 必要に応じて他のスタイルを追加
]
}
このJSON構造は、以下の要素で構成される。
- `paragraphStyles`: 段落スタイル定義の配列。
- `name`: スタイルの識別子(VBAコードから参照する際に使用)。
- `font`: フォント設定オブジェクト。
- `name`: フォント名。
- `size`: フォントサイズ(ポイント)。
- `bold`: 太字(Boolean)。
- `italic`: 斜体(Boolean)。
- `color`: フォントの色(RGBの16進数文字列)。
- `paragraphFormat`: 段落書式設定オブジェクト。
- `lineSpacing`: 行間(倍数、固定値、最小値など、Wordの行間設定に合わせた表現を検討)。
- `spaceBefore`: 段落前の間隔(ポイント)。
- `spaceAfter`: 段落後の間隔(ポイント)。
- `leftIndent`: 左インデント(ポイント)。
- `firstLineIndent`: ぶら下げインデント、または最初の行のインデント(ポイント)。
RGBカラーコードの扱いに注意
JSONで色を`”000000″`のような16進数文字列で表現した場合、VBAで`RGB(red, green, blue)`関数で直接利用するには変換が必要となる。これは、Windows APIの`COLORREF`構造体との親和性を考慮した結果でもある。VBAでは`Long`型として扱えるように、16進数文字列を数値に変換する処理を実装する必要がある。
VBAでの実装 – JSONの読み込みと適用
JSONファイルを読み込み、パースし、Wordの段落に適用するVBAコードを実装する。ここでは、`Microsoft Scripting Runtime`(FileSystemObject)と、JSONパーサーライブラリ(またはXMLHTTP6.0など、JSONを扱えるオブジェクト)を利用する。
注意: VBA標準機能でJSONを直接パースするのは困難なため、外部ライブラリやAPIを利用するのが一般的だ。ここでは、`Microsoft XML, v6.0`(または`v3.0`)を利用してJSONを読み込み、その構造を操作する例を示す。これにより、Windows APIの利用にも繋がる。
まず、VBAエディタで「ツール」->「参照設定」から「Microsoft Scripting Runtime」と「Microsoft XML, v6.0」にチェックを入れる。
Option Explicit
‘ — 定数定義 —
Const JSON_FILE_PATH As String = “C:\Path\To\Your\paragraph_styles.json” ‘ JSONファイルのパスを適切に設定
‘ — JSON関連の型定義 (必要に応じて拡張) —
‘ JSON構造を模倣したクラスモジュールを作成すると、よりオブジェクト指向的に扱えるが、
‘ ここでは簡潔にするため、Dictionaryオブジェクトで代用する。
‘ 実際には、JSONパーサーライブラリが提供する型定義を利用するか、
‘ 独自のクラスを作成することを推奨する。
‘ — メイン処理: 指定した段落にJSONから読み込んだスタイルを適用 —
Sub ApplyParagraphStyleFromJson(targetParagraph As Paragraph, styleName As String)
Dim jsonText As String
Dim jsonObject As Object ‘ Scripting.Dictionary または MSXML2.DOMDocument60
Dim stylesArray As Object ‘ Scripting.Collection または Variant (Array)
Dim style As Object ‘ Scripting.Dictionary
Dim fontSettings As Object
Dim paraFormatSettings As Object
Dim i As Long
Dim targetFont As Font
Dim targetParaFormat As ParagraphFormat
‘ — 1. JSONファイルの読み込み —
On Error GoTo ErrorHandler
jsonText = ReadJsonFile(JSON_FILE_PATH)
If jsonText = “” Then
MsgBox “JSONファイルの読み込みに失敗しました。”, vbCritical
Exit Sub
End If
‘ — 2. JSONのパース (MSXML2.DOMDocument60 を利用) —
‘ MSXML2.DOMDocument60 は XML パーサーだが、LoadXML メソッドで JSON もある程度扱える。
‘ より高度な JSON パースには、JSON パーサーライブラリの利用を推奨。
Set jsonObject = CreateObject(“MSXML2.DOMDocument.6.0”)
jsonObject.LoadXML jsonText
‘ JSON のルート要素(ここでは “paragraphStyles”)を取得
‘ DOMDocument の場合、直接的な JSON オブジェクト操作は限定的。
‘ ここでは、JSON を Dictionary に変換するヘルパー関数を想定する。
‘ 簡易的な例として、JSON文字列を Dictionary へ変換する処理を記述。
‘ 実際には、より堅牢な JSON パーサーライブラリ (例: VBA-JSON) の利用を強く推奨。
‘ — 簡易的なJSONパース (Dictionary利用) —
‘ 実際には、JSON文字列を適切にパースし、Dictionary や Collection に変換する処理が必要。
‘ ここでは、JSON文字列が既に Dictionary オブジェクトに変換されていると仮定する。
‘ (例: VBA-JSON ライブラリでパースした場合など)
‘ 以下のコードは、JSON.parse(jsonText) が Dictionary を返すと仮定した擬似コードです。
‘ Dim parsedJson As Object
‘ Set parsedJson = JsonConverter.Parse(jsonText) ‘ VBA-JSON の場合
‘ Set stylesArray = parsedJson(“paragraphStyles”)
‘ — MSXML2.DOMDocument60 での簡易的なデータ取得例 (XPathなど活用) —
‘ DOMDocument は XML 用なので、JSON の直接的な要素アクセスには不向き。
‘ ここでは、JSON を Dictionary へ変換する helper を呼び出す前提で進める。
‘ 実際には、JSONパーサーライブラリ (例: VBA-JSON) を使うのが最も効率的。
‘ — 便宜上、JSON 文字列を直接 Dictionary に変換する処理を模倣 —
‘ 実際には、上記のようなライブラリを使用してください。
Dim parsedJson As Object
Set parsedJson = ParseJsonStringIntoDictionary(jsonText) ‘ ★この関数は別途実装が必要
If parsedJson Is Nothing Then
MsgBox “JSON のパースに失敗しました。”, vbCritical
Exit Sub
End If
Set stylesArray = parsedJson(“paragraphStyles”)
‘ — 3. 指定されたスタイルの検索 —
Set style = FindStyleByName(stylesArray, styleName)
If style Is Nothing Then
MsgBox “スタイル ‘” & styleName & “‘ がJSONファイルに見つかりませんでした。”, vbExclamation
Exit Sub
End If
‘ — 4. 書式設定の適用 —
‘ フォント設定の適用
Set fontSettings = style(“font”)
Set targetFont = targetParagraph.Range.Font
‘ フォント名、サイズ、太字、斜体
With targetFont
.Name = CStr(fontSettings(“name”))
.Size = CDbl(fontSettings(“size”))
.Bold = CBool(fontSettings(“bold”))
.Italic = CBool(fontSettings(“italic”))
‘ フォントカラーの変換 (Hex String to RGB Long)
Dim hexColor As String
Dim rgbColor As Long
hexColor = CStr(fontSettings(“color”))
rgbColor = HexToRgb(hexColor)
.Color = rgbColor
End With
‘ ———————————————-
‘ ★メモリ最適化: FontオブジェクトはRangeオブジェクトのプロパティとして取得されるため、
‘ 直接的な解放は不要だが、不要になったRangeオブジェクトは解放を検討。
‘ ここでは、targetParagraph は外部から渡されるため、解放は呼び出し元に委ねる。
‘ ———————————————-
‘ 段落書式設定の適用
Set paraFormatSettings = style(“paragraphFormat”)
Set targetParaFormat = targetParagraph.ParagraphFormat
With targetParaFormat
‘ 行間 (Wordの行間設定は多様なため、倍数での設定を基本とする)
‘ Wordの行間設定は、wdLineSpaceSingle, wdLineSpace1pt5, wdLineSpaceDouble, wdLineSpaceAtLeast, wdLineSpaceExactly, wdLineSpaceMultiply などがある。
‘ JSONでは倍数 (Multiply) で定義するのが最も汎用的。
.LineSpacingRule = wdLineSpacingMultiply ‘ 倍数指定
.LineSpacing = CDbl(paraFormatSettings(“lineSpacing”))
‘ 段落前後の間隔
.SpaceBefore = CDbl(paraFormatSettings(“spaceBefore”))
.SpaceAfter = CDbl(paraFormatSettings(“spaceAfter”))
‘ インデント (ポイント単位)
.LeftIndent = CDbl(paraFormatSettings(“leftIndent”))
.FirstLineIndent = CDbl(paraFormatSettings(“firstLineIndent”))
End With
‘ ———————————————-
‘ ★メモリ最適化: ParagraphFormatオブジェクトも同様に、Paragraphオブジェクトのプロパティ。
‘ ———————————————-
‘ — 5. オブジェクトの解放 (明示的な解放) —
‘ 参照をクリアし、メモリを解放する。
Set fontSettings = Nothing
Set paraFormatSettings = Nothing
Set targetFont = Nothing
Set targetParaFormat = Nothing
Set style = Nothing
Set stylesArray = Nothing
Set jsonObject = Nothing
Set parsedJson = Nothing
Exit Sub
ErrorHandler:
MsgBox “エラーが発生しました: ” & Err.Description & ” (コード: ” & Err.Number & “)”, vbCritical
‘ エラー発生時も、作成されたオブジェクトの解放を試みる
On Error Resume Next ‘ エラー発生時でも解放処理を続行
Set fontSettings = Nothing
Set paraFormatSettings = Nothing
Set targetFont = Nothing
Set targetParaFormat = Nothing
Set style = Nothing
Set stylesArray = Nothing
Set jsonObject = Nothing
Set parsedJson = Nothing
Err.Clear ‘ エラーオブジェクトをクリア
End Sub
‘ — ヘルパー関数: JSONファイルを読み込む —
‘ FileSystemObject を利用して、指定されたパスのファイルをテキストとして読み込む
Private Function ReadJsonFile(filePath As String) As String
Dim fso As Object ‘ Scripting.FileSystemObject
Dim ts As Object ‘ Scripting.TextStream
On Error GoTo ErrorHandler
Set fso = CreateObject(“Scripting.FileSystemObject”)
If Not fso.FileExists(filePath) Then
MsgBox “指定されたJSONファイルが存在しません: ” & filePath, vbCritical
ReadJsonFile = “”
Exit Function
End If
Set ts = fso.OpenTextFile(filePath, 1, False, -2) ‘ ForReading, Unicode
ReadJsonFile = ts.ReadAll
ts.Close
‘ — メモリ最適化: オブジェクトの解放 —
Set ts = Nothing
Set fso = Nothing
Exit Function
ErrorHandler:
MsgBox “JSONファイルの読み込み中にエラーが発生しました: ” & Err.Description, vbCritical
ReadJsonFile = “”
On Error Resume Next ‘ エラー発生時でも解放処理を続行
If Not ts Is Nothing Then ts.Close
Set ts = Nothing
Set fso = Nothing
Err.Clear
End Function
‘ — ヘルパー関数: スタイル名でスタイルオブジェクトを検索 —
Private Function FindStyleByName(stylesArray As Object, styleName As String) As Object
Dim item As Variant
Dim currentStyleName As String
On Error Resume Next ‘ エラー処理を有効にする
‘ Dictionary を想定したループ
If TypeName(stylesArray) = “Dictionary” Then
Dim keys As Variant
keys = stylesArray.Keys
For Each item In keys
Set FindStyleByName = stylesArray(item)
If TypeName(FindStyleByName) = “Dictionary” Then ‘ 要素が Dictionary であることを確認
currentStyleName = CStr(FindStyleByName(“name”))
If StrComp(currentStyleName, styleName, vbTextCompare) = 0 Then
‘ 見つかったスタイルオブジェクトを返す
Exit Function
End If
End If
Set FindStyleByName = Nothing ‘ 初期化
Next item
ElseIf TypeName(stylesArray) = “Collection” Then ‘ Collection の場合
For Each item In stylesArray
If TypeName(item) = “Dictionary” Then ‘ 要素が Dictionary であることを確認
currentStyleName = CStr(item(“name”))
If StrComp(currentStyleName, styleName, vbTextCompare) = 0 Then
Set FindStyleByName = item
Exit Function
End If
End If
Next item
ElseIf IsArray(stylesArray) Then ‘ Array の場合
Dim element As Variant
For Each element In stylesArray
If IsObject(element) Then
If TypeName(element) = “Dictionary” Then
currentStyleName = CStr(element(“name”))
If StrComp(currentStyleName, styleName, vbTextCompare) = 0 Then
Set FindStyleByName = element
Exit Function
End If
End If
End If
Next element
End If
‘ 見つからなかった場合は Nothing を返す
Set FindStyleByName = Nothing
On Error GoTo 0 ‘ エラー処理を元に戻す
End Function
‘ — ヘルパー関数: 16進数カラーコード文字列をRGB Long値に変換 —
‘ 例: “000000” -> 0, “FF0000” -> 255
Private Function HexToRgb(hexColor As String) As Long
Dim r As Long, g As Long, b As Long
Dim subHex As String
If Len(hexColor) <> 6 Then
HexToRgb = 0 ‘ 不正なフォーマットの場合は黒を返す
Exit Function
End If
On Error Resume Next ‘ エラー処理を有効にする
‘ R G B の順で抽出
subHex = Mid(hexColor, 1, 2) ‘ RR
r = CLng(“&H” & subHex)
subHex = Mid(hexColor, 3, 2) ‘ GG
g = CLng(“&H” & subHex)
subHex = Mid(hexColor, 5, 2) ‘ BB
b = CLng(“&H” & subHex)
If Err.Number <> 0 Then
HexToRgb = 0 ‘ 変換エラー時は黒を返す
Err.Clear
Exit Function
End If
‘ VBAのRGB関数は R, G, B の順で引数を取る
HexToRgb = RGB(r, g, b)
On Error GoTo 0 ‘ エラー処理を元に戻す
End Function
‘ — ★JSONパースの代替実装 (簡易版) —
‘ 実際には VBA-JSON などのライブラリを使用してください。
‘ この関数は、JSON文字列を Dictionary オブジェクトのネスト構造に変換します。
‘ 非常に限定的な JSON 構文のみをサポートします。
Private Function ParseJsonStringIntoDictionary(jsonString As String) As Object
Dim parsed As Object
Dim jsonParser As Object ‘ JSONパーサーオブジェクト
‘ — 外部JSONパーサーライブラリの利用を推奨 —
‘ 例: VBA-JSON (https://github.com/VBA-tools/VBA-JSON)
‘ このライブラリをプロジェクトに追加し、JsonConverter.Parse メソッドを使用するのが最も簡単で堅牢です。
‘ Set jsonParser = JsonConverter ‘ VBA-JSON の場合
‘ Set parsed = jsonParser.Parse(jsonString)
‘ — ここでは、MSXML2.DOMDocument60 を使って簡易的にパースする例を示す —
‘ ただし、DOMDocument は XML 用であり、JSON の直接的なパースは限定的です。
‘ JSON の構造によっては、この方法ではうまくパースできません。
Dim xmlDoc As Object
Set xmlDoc = CreateObject(“MSXML2.DOMDocument.6.0”)
xmlDoc.LoadXML “
If xmlDoc.parseError.errorCode <> 0 Then
MsgBox “XMLとしてロードできませんでした。JSON構文エラーの可能性があります。”, vbCritical
Set ParseJsonStringIntoDictionary = Nothing
Exit Function
End If
‘ DOMDocument から Dictionary への変換は複雑なため、
‘ ここでは、JSON文字列を直接 Dictionary に変換するロジックを模倣する。
‘ 実際には、以下のような処理を自作するか、ライブラリを使用する。
‘ — 簡易的な Dictionary への変換ロジック (再帰的に処理) —
‘ この関数は、JSON文字列を解析し、Dictionaryオブジェクトの階層構造を返します。
‘ 実際のJSONパーサーライブラリに匹敵する機能はありません。
Set ParseJsonStringIntoDictionary = CreateObject(“Scripting.Dictionary”)
Dim tempJson As String
tempJson = Trim(jsonString)
If Left(tempJson, 1) = “{” And Right(tempJson, 1) = “}” Then
tempJson = Mid(tempJson, 2, Len(tempJson) – 2) ‘ {} を除去
Dim pairs() As String
pairs = Split(tempJson, “,”) ‘ 簡単な分割 (ネストされたオブジェクトや配列には対応しない)
Dim pair As Variant
Dim kv() As String
Dim key As String, valStr As String
For Each pair In pairs
kv = Split(pair, “:”, 2) ‘ キーと値に分割
If UBound(kv) = 1 Then
key = Trim(kv(0))
valStr = Trim(kv(1))
‘ キーのクォーテーションを除去
If Left(key, 1) = “””” And Right(key, 1) = “””” Then
key = Mid(key, 2, Len(key) – 2)
End If
‘ 値の解析 (文字列、数値、ブール値、null、オブジェクト、配列)
Dim parsedValue As Variant
parsedValue = ParseJsonValue(valStr)
If Not parsedValue Is Nothing Then
ParseJsonStringIntoDictionary.Add key, parsedValue
End If
End If
Next pair
ElseIf Left(tempJson, 1) = “[” And Right(tempJson, 1) = “]” Then
‘ 配列の処理 (ここではDictionaryではなくCollectionで返す)
Set ParseJsonStringIntoDictionary = CreateObject(“System.Collections.ArrayList”) ‘ ArrayList を使用
tempJson = Mid(tempJson, 2, Len(tempJson) – 2)
Dim elements() As String
elements = Split(tempJson, “,”) ‘ 簡単な分割
Dim element As Variant
For Each element In elements
Dim parsedElement As Variant
parsedElement = ParseJsonValue(Trim(element))
If Not parsedElement Is Nothing Then
ParseJsonStringIntoDictionary.Add parsedElement
End If
Next element
End If
‘ ★重要: 上記の ParseJsonStringIntoDictionary 関数は、JSON の一部の構文しかサポートしていません。
‘ 実際の運用では、VBA-JSON などの実績のあるライブラリを使用することを強く推奨します。
‘ ここでは、動作原理を示すための「モック」として実装しています。
Set xmlDoc = Nothing ‘ オブジェクト解放
End Function
‘ — 簡易JSON値解析ヘルパー —
Private Function ParseJsonValue(valStr As String) As Variant
valStr = Trim(valStr)
‘ null
If StrComp(valStr, “null”, vbTextCompare) = 0 Then
Set ParseJsonValue = Nothing
Exit Function
End If
‘ Boolean (true/false)
If StrComp(valStr, “true”, vbTextCompare) = 0 Then
ParseJsonValue = True
Exit Function
End If
If StrComp(valStr, “false”, vbTextCompare) = 0 Then
ParseJsonValue = False
Exit Function
End If
‘ String (“…”)
If Left(valStr, 1) = “””” And Right(valStr, 1) = “””” Then
ParseJsonValue = Mid(valStr, 2, Len(valStr) – 2)
Exit Function
End If
‘ Number (Integer/Decimal)
If IsNumeric(valStr) Then
ParseJsonValue = CDbl(valStr) ‘ Double で受け取ることで整数・小数両方に対応
Exit Function
End If
‘ Object ({…}) – 再帰呼び出し
If Left(valStr, 1) = “{” And Right(valStr, 1) = “}” Then
Dim subObj As Object
Set subObj = ParseJsonStringIntoDictionary(valStr) ‘ 再帰呼び出し
Set ParseJsonValue = subObj
Exit Function
End If
‘ Array ([…]) – 再帰呼び出し
If Left(valStr, 1) = “[” And Right(valStr, 1) = “]” Then
Dim subArray As Object
Set subArray = ParseJsonStringIntoDictionary(valStr) ‘ 再帰呼び出し
Set ParseJsonValue = subArray
Exit Function
End If
‘ 解析できなかった場合は、そのまま文字列として返すか、Nothing を返す
‘ ここでは、解析できなかったものは Nothing とする
Set ParseJsonValue = Nothing
End Function
‘ — 実行例 —
Sub Example_ApplyStyle()
Dim doc As Document
Dim para As Paragraph
Dim targetStyle As String
Set doc = ActiveDocument
‘ 例: 最初の段落に “Heading1” スタイルを適用
If doc.Paragraphs.Count > 0 Then
Set para = doc.Paragraphs(1)
targetStyle = “Heading1” ‘ JSONファイルで定義したスタイル名
ApplyParagraphStyleFromJson para, targetStyle
MsgBox “最初の段落に ‘” & targetStyle & “‘ スタイルが適用されました。”, vbInformation
Else
MsgBox “文書に段落がありません。”, vbInformation
End If
‘ 例: 2番目の段落に “IndentedText” スタイルを適用
If doc.Paragraphs.Count > 1 Then
Set para = doc.Paragraphs(2)
targetStyle = “IndentedText”
ApplyParagraphStyleFromJson para, targetStyle
MsgBox “2番目の段落に ‘” & targetStyle & “‘ スタイルが適用されました。”, vbInformation
End If
‘ オブジェクト解放
Set para = Nothing
Set doc = Nothing
End Sub
コード解説と知見
1. `ApplyParagraphStyleFromJson` サブルーチン:
- `targetParagraph` (Paragraphオブジェクト) と `styleName` (String) を引数に取ります。
- `ReadJsonFile` 関数で JSON ファイルの内容を文字列として読み込みます。
- JSON パース: `MSXML2.DOMDocument.6.0` を利用する例を示していますが、これは XML パーサーであり、JSON の直接的なパースには限界があります。本番環境では、VBA-JSON のような実績のある JSON パーサーライブラリの利用を強く推奨します。 ここでは、`ParseJsonStringIntoDictionary` という「モック」関数を別途実装し、JSON 文字列を `Scripting.Dictionary` や `System.Collections.ArrayList` に変換する処理を模倣しています。
- `FindStyleByName` 関数で、JSON データから指定された `styleName` に合致するスタイル定義を探します。
- 見つかったスタイル定義に基づき、`targetParagraph.Range.Font` および `targetParagraph.ParagraphFormat` プロパティを更新します。
- `HexToRgb` 関数は、JSON で定義された 16 進数カラーコードを VBA の `RGB` 関数が扱える `Long` 型に変換します。これは、Windows API における COLORREF 型との親和性を意識した実装です。
- メモリ最適化: 各オブジェクト (`fontSettings`, `paraFormatSettings` など) は、使用後に `Set obj = Nothing` で明示的に解放しています。これにより、VBA のガベージコレクションに頼りすぎるのではなく、リソースを積極的に管理します。これは、特にループ内で大量のオブジェクトを生成・破棄する場合に、パフォーマンスの安定化に不可欠です。
2. `ReadJsonFile` 関数:
- `FileSystemObject` を使用して、指定されたパスのファイルを読み込みます。
- ファイルが存在しない場合のエラーハンドリングを実装しています。
- メモリ最適化: `fso` と `ts` オブジェクトも、使用後に解放しています。
3. `FindStyleByName` 関数:
- JSON からパースされたデータ(ここでは `Dictionary` や `Collection` を想定)を検索し、指定されたスタイル名に一致する要素を返します。
- `StrComp` 関数を `vbTextCompare` オプション付きで使用し、大文字・小文字を区別せずに比較しています。
4. `HexToRgb` 関数:
- 6桁の16進数文字列(例: “FF0000″)を VBA の `RGB(Red, Green, Blue)` 関数で扱える `Long` 型数値に変換します。
- `CLng(“&H” & subHex)` を利用して、16進数文字列を10進数の `Long` 型に変換しています。
5. `ParseJsonStringIntoDictionary` / `ParseJsonValue` 関数 (簡易版):
- これらの関数は、JSON 文字列を VBA の `Scripting.Dictionary` や `System.Collections.ArrayList` に変換するための 「モック」実装 です。
- JSON のネスト構造、文字列、数値、ブール値、null を基本的なレベルで処理します。
- 重要: この簡易実装は、JSON の複雑な構文(エスケープシーケンス、配列内のカンマ、オブジェクト内のカンマなど)には対応していません。実際の開発では、VBA-JSON のような専用ライブラリを利用することを強く推奨します。 ライブラリを使用することで、コードの堅牢性と保守性が飛躍的に向上します。
6. `Example_ApplyStyle` サブルーチン:
- 実際に `ApplyParagraphStyleFromJson` を呼び出す例を示しています。
- アクティブドキュメントの最初の段落に “Heading1″、2番目の段落に “IndentedText” スタイルを適用しています。
レガシー環境とシステム間連携の極限
このJSON管理アプローチは、レガシー環境の保守において特に真価を発揮します。
- 改修コストの最小化: 書式設定の変更要求があった場合、VBAコードを一切触らずにJSONファイルを編集するだけで対応できます。これにより、テスト範囲を限定でき、改修に伴うリスクを大幅に低減できます。
- バージョン管理の容易さ: JSONファイルはプレーンテキストなので、Gitなどのバージョン管理システムで容易に管理できます。書式設定の変更履歴を追跡し、必要に応じて過去のバージョンに戻すことも容易です。
- システム間連携への布石: JSONは、他のシステム(Webアプリケーション、データベース、他のスクリプト言語など)とのデータ連携において、デファクトスタンダードとも言えるフォーマットです。このアプローチを採用することで、将来的にWord文書の書式設定を、外部システムから動的に生成・管理するような、より高度なシステム連携も視野に入れることができます。例えば、Webフォームで入力された内容に応じて、Word文書の特定の段落スタイルを動的に変更するといったシナリオが考えられます。
Windows APIとの連携とパフォーマンスの深淵
直接的なWindows APIの呼び出しは、このJSON管理アプローチでは必須ではありません。しかし、JSONパーサーライブラリの内部や、より高度な書式設定(例えば、特定のフォントグリッドへの配置など)を実装する際には、Windows APIの知識が役立つ場面が出てきます。
- `CreateObject(“MSXML2.DOMDocument.6.0”)`: これは COM オブジェクトの生成であり、内部的には Windows API を介してリソースが管理されています。
- メモリ管理: VBA におけるオブジェクトのライフサイクル管理は、Windows のメモリ管理機構の上に成り立っています。`Set obj = Nothing` による明示的な解放は、VBA のオブジェクトモデルを通じて、基盤となる Windows API にリソース解放のシグナルを送っているのです。
- パフォーマンスチューニング: 大量の段落に一括でスタイルを適用する場合、1つ1つの段落に対して `ApplyParagraphStyleFromJson` を呼び出すのではなく、処理をバッチ化し、Word の `ScreenUpdating` や `Calculation` プロパティをオフにすることで、パフォーマンスを大幅に向上させることができます。これは、API レベルでの最適化と言えます。
Sub ApplyStylesInBatch(styleName As String)
Dim doc As Document
Dim para As Paragraph
Set doc = ActiveDocument
‘ — パフォーマンス向上のための設定 —
Application.ScreenUpdating = False ‘ 画面描画を無効化
Application.Calculation = wdCalculationManual ‘ 自動計算を無効化
On Error GoTo ErrorHandler ‘ エラー発生時の復旧処理
‘ 全ての段落にスタイルを適用
For Each para In doc.Paragraphs
ApplyParagraphStyleFromJson para, styleName ‘ JSONからスタイルを適用する関数を呼び出す
‘ — メモリ最適化: ループ内でのオブジェクト解放 —
‘ ApplyParagraphStyleFromJson 内でオブジェクトは解放されるが、
‘ Paragraph オブジェクト自体も不要になったら解放を検討 (ここではループ変数なので自動管理)
Set para = Nothing ‘ 明示的に解放 (必須ではないが、大規模処理では有効な場合も)
Next para
‘ — 処理完了後の設定復元 —
Application.ScreenUpdating = True
Application.Calculation = wdCalculationAutomatic ‘ 自動計算を有効化
MsgBox “指定されたスタイル ‘” & styleName & “‘ が文書全体に適用されました。”, vbInformation
Exit Sub
ErrorHandler:
MsgBox “バッチ処理中にエラーが発生しました: ” & Err.Description, vbCritical
‘ エラー発生時も、画面更新と計算設定を元に戻す
Application.ScreenUpdating = True
Application.Calculation = wdCalculationAutomatic
Err.Clear
End Sub
まとめ
JSON による段落書式設定の外部管理は、VBA における「ハードコーディング」の呪縛から逃れ、より柔軟で保守性の高いシステムを構築するための強力なアプローチです。これは単にコードを綺麗にするだけでなく、オブジェクトのライフサイクル管理、パフォーマンスへの配慮、そして将来的なシステム連携までを見据えた、アーキテクトとしての洞察が求められる領域です。
貴殿らが日々向き合っている Word VBA の世界は、まだまだ奥深い。この知見が、貴殿らの自動化プロジェクトを次のレベルへと引き上げる一助となれば幸いだ。技術の真髄を追求し、真の効率化を達成せんことを。
