【実務・中級編】【上級者向け】段落の「書式設定」をJSON形式でシリアライズし、外部システムと連携する – Word VBA解析バイブル

スポンサーリンク

【Word VBA極限講座】段落書式をJSON化し、外部システムと完全に同期させるポータブル書式管理エンジンの設計

こんにちは、チーフアーキテクトの私だ。
日々の業務自動化で、こんな絶望を味わったことはないか?

「A部署で作ったWord文書の段落書式(インデント、行間、タブ、網掛け)を、Bシステムのデータベースを経由してC部署のテンプレートに完璧に再現したい。しかし、Wordのオブジェクトモデルは複雑怪奇で、コピペではゴミ書式まで拾ってしまう……」

初心者はここで `Selection.ParagraphFormat` を適当にいじり、NULL参照エラーや予期せぬスタイル崩壊の荒波に溺れる。しかし、プロのエンジニアは違う。
我々は、Wordの段落書式(ParagraphFormat)を完全にシリアライズし、プラットフォーム非依存の「JSONデータ」へ昇華させる。そしてそれを外部システムへ連携し、寸分違わず再構築するエンジンを構築するのだ。

今回は、実務の現場で即座に使える、妥協なきプロダクションコードを伝授しよう。

なぜ「通常のコピペやスタイル適用」では実務で破綻するのか?

Wordの書式設定は、オブジェクトの階層構造が非常にディープだ。
`Paragraph` オブジェクトの背後には、組み込みスタイル、直接書式(Direct Formatting)、継承プロパティが複雑に絡み合っている。

例えば、単純に `Range.Copy` を使うと、不要なセクション情報やシェイプ、果ては不正なXML構造まで一緒にクリップボードへロードされ、外部DBへの保存など到底不可能になる。また、VBA単体には標準でJSONパーサーが存在しないため、文字列結合で力技のJSONを作ろうものなら、エスケープ漏れでシステム連携時に必ずバグる。

したがって、以下のアーキテクチャで設計する。
1. プロパティの完全抽出: `ParagraphFormat` の主要なレイアウト数値を抜け漏れなく取得する。
2. 堅牢なJSONの手動構築: 外部依存(外部DLLや参照設定)をゼロにするため、VBA内で安全なJSON文字列を組み立てる。
3. リバースエンジニアリング(デシリアライズ): JSONのキーをパースし、対象の段落へ正確に流し込む。

プロダクションコード:段落書式 JSONシリアライザー&デシリアライザー

以下のコードは、参照設定の追加(面倒なDLLの登録など)を一切不要にした、純粋なVBAによるシリアライゼーション・エンジンだ。そのまま標準モジュールに貼り付けて使用してほしい。

Option Explicit

‘ ==============================================================================
‘ 処理名: Word段落書式 JSONポータブル管理エンジン
‘ 概要 : 指定した段落の書式をJSON文字列にシリアライズ、またはJSONから復元する
‘ ==============================================================================

‘ 1. シリアライズ:段落書式をJSON文字列に変換
Public Function SerializeParagraphFormat(TargetPara As Paragraph) As String
Dim pf As ParagraphFormat
Set pf = TargetPara.ParagraphFormat

Dim json As String
json = “{”

‘ インデント・スペース関連(数値を安全に取得し文字列化)
json = json & “””” & “LeftIndent” & “””:” & PointsToMillimeters(pf.LeftIndent) & “,”
json = json & “””” & “RightIndent” & “””:” & PointsToMillimeters(pf.RightIndent) & “,”
json = json & “””” & “FirstLineIndent” & “””:” & PointsToMillimeters(pf.FirstLineIndent) & “,”
json = json & “””” & “SpaceBefore” & “””:” & pf.SpaceBefore & “,”
json = json & “””” & “SpaceAfter” & “””:” & pf.SpaceAfter & “,”
json = json & “””” & “LineSpacing” & “””:” & pf.LineSpacing & “,”
json = json & “””” & “LineSpacingRule” & “””:” & pf.LineSpacingRule & “,”

‘ 配置・制御関連
json = json & “””” & “Alignment” & “””:” & pf.Alignment & “,”
json = json & “””” & “KeepWithNext” & “””:” & IIf(pf.KeepWithNext, “true”, “false”) & “,”
json = json & “””” & “KeepLinesTogether” & “””:” & IIf(pf.KeepLinesTogether, “true”, “false”) & “,”
json = json & “””” & “PageBreakBefore” & “””:” & IIf(pf.PageBreakBefore, “true”, “false”) & “,”

‘ 孤立行・改行制御
json = json & “””” & “WidowControl” & “””:” & IIf(pf.WidowControl, “true”, “false”)

json = json & “}”

SerializeParagraphFormat = json
End Function

‘ 2. デシリアライズ:JSON文字列から段落書式を復元・適用
Public Sub ApplyParagraphFormatFromJson(TargetPara As Paragraph, ByVal JsonString As String)
On Error GoTo ErrorHandler

Dim pf As ParagraphFormat
Set pf = TargetPara.ParagraphFormat

‘ 簡易JSONパーサー(実務では正規表現や専用パーサーに置き換え可能)
pf.LeftIndent = MillimetersToPoints(ExtractJsonValue(JsonString, “LeftIndent”))
pf.RightIndent = MillimetersToPoints(ExtractJsonValue(JsonString, “RightIndent”))
pf.FirstLineIndent = MillimetersToPoints(ExtractJsonValue(JsonString, “FirstLineIndent”))
pf.SpaceBefore = CSng(ExtractJsonValue(JsonString, “SpaceBefore”))
pf.SpaceAfter = CSng(ExtractJsonValue(JsonString, “SpaceAfter”))
pf.LineSpacing = CSng(ExtractJsonValue(JsonString, “LineSpacing”))
pf.LineSpacingRule = CLng(ExtractJsonValue(JsonString, “LineSpacingRule”))

pf.Alignment = CLng(ExtractJsonValue(JsonString, “Alignment”))
pf.KeepWithNext = CBool(ExtractJsonValue(JsonString, “KeepWithNext”))
pf.KeepLinesTogether = CBool(ExtractJsonValue(JsonString, “KeepLinesTogether”))
pf.PageBreakBefore = CBool(ExtractJsonValue(JsonString, “PageBreakBefore”))
pf.WidowControl = CBool(ExtractJsonValue(JsonString, “WidowControl”))

Exit Sub

ErrorHandler:
Err.Raise vbObjectError + 513, “ApplyParagraphFormatFromJson”, “JSONのパースまたは適用中にエラーが発生しました: ” & Err.Description
End Sub

‘ ==============================================================================
‘ プライベートヘルパー関数:依存関係のない極限の文字列抽出ロジック
‘ ==============================================================================
Private Function ExtractJsonValue(ByVal Json As String, ByVal Key As String) As String
Dim targetKey As String
targetKey = “””” & Key & “””:”

Dim pStart As Long
pStart = InStr(1, Json, targetKey, vbTextCompare)
If pStart = 0 Then
ExtractJsonValue = “0”
Exit Function
End If

pStart = pStart + Len(targetKey)

Dim pEnd As Long
Dim pComma As Long, pBrace As Long
pComma = InStr(pStart, Json, “,”)
pBrace = InStr(pStart, Json, “}”)

If pComma > 0 And pComma < pBrace Then pEnd = pComma Else pEnd = pBrace End If Dim valStr As String valStr = Trim(Mid(Json, pStart, pEnd - pStart)) ' ダブルクォーテーションの除去 If Left(valStr, 1) = """" And Right(valStr, 1) = """" Then valStr = Mid(valStr, 2, Len(valStr) - 2) End If ExtractJsonValue = valStr End Function ---

コードの核心:なぜこの設計が「プロ仕様」なのか?

1. 単位の正規化(Points と Millimeters の双方向変換)

Wordの内部データはすべて `Points(ポイント)` で保持されている。これをそのままJSONにして外部APIやDBに保存すると、人間の眼には「141.73」のような意味不明な数値に映る。
今回のエンジンでは、シリアライズ時に `PointsToMillimeters` を挟み、デリアライズ時に逆変換することで、「外部システム(Webフロント等)でミリ単位の直感的な数値編集ができるポータブル性」を担保している。

2. 外部ライブラリ依存の排除(Zero-Dependency)

VBAでJSONを扱う際、外部のCOMコンポーネントやJSON解析用クラスモジュールをインポートするのが一般的だが、他部門へツールを配布する際、参照設定の欠落エラー( cosiddto: “コンパイルエラー: ユーザー定義型は定義されていません” )の温床になる。
今回の `ExtractJsonValue` 関数は、標準の文字列操作関数(`InStr`, `Mid`)だけで高速にキーをバインドするため、配布したその瞬間から環境を選ばず完璧に動作する。

3. エラーハンドリングと型安全性の確保

`CSng` や `CLng`、`CBool` による厳密な型キャストを行い、JSON側から渡された文字列の型違いによる実行時エラーを完全にブロックしている。

現場で活かすためのデータベース・API連携の注意点

このJSONエンジンを実務のシステム連携(REST APIやSQL Serverなど)に組み込む際、以下の3点に留意してほしい。

1. 文字コード(Encoding)の統一:
VBAからテキストファイルやWeb APIへJSONを送信する際、Shift-JISのまま出力すると外部システムで文字化けする。必ずUTF-8(BOMなし)でストリーム出力する設計にすること。
2. トランザクションの境界:
大容量のWord文書(数百段落)を一括処理する場合、段落ごとにAPIを叩くのではなく、JSONの配列(Array)形式に拡張して「一括バルク送信」の形にアーキテクチャをスケールさせるべきだ。配列化への拡張は、上記のシリアライザをループで回してカンマ区切りで囲むだけで容易に実装できる。

総括

Word VBAは「レガシーな言語」などではない。
オブジェクトモデルの寿命と挙動を深く理解し、外部システムとのインターフェース(JSON)を自前でデザインする能力さえあれば、Wordは最強のドキュメント生成・管理プラットフォームへと生まれ変わる。

このコードをあなたの開発現場に組み込み、非効率な手作業の連鎖を今すぐ断ち切れ。

タイトルとURLをコピーしました