【入門編】【上級者向け】カスタムフィールドの値をJSON形式でエクスポート・インポートする – Project VBA解析バイブル

スポンサーリンク
スポンサーリンク

MS Projectを「孤島」から「エコシステム」へ。カスタムフィールドをJSONで繋ぐ、極限のデータ連携術

こんにちは。現場の泥臭い自動化から、大規模システムのアーキテクチャ設計まで渡り歩いてきた、あなたの頼れる先輩エンジニアです。

「マクロの記録」でボタン一つ動かせるようになった。
「基本的なループ処理」でセルの値を書き換えられるようになった。

ここまで来られたあなたは、もう初級者ではありません。しかし、もしあなたが「MS Projectで管理している複雑なカスタムフィールドのデータを、Webシステムや他のツールと連携させたい」と願っているなら、まだ大きな壁が立ちはだかっているはずです。

MS Projectのカスタムフィールド(`Text1`や`Number1`など)は、非常に便利ですが、外部から見ると「中身が何かわからない、ただの箱」に過ぎません。この「意味(セマンティクス)の欠如」を解決し、データをモダンなJSON形式でやり取りする技術を身につければ、あなたの業務自動化は「単なる作業の効率化」から「システム間の統合」へと進化します。

今日は、そのための極限の知見を、コードと共に伝授しましょう。

1. なぜ「JSON」なのか? MS Projectの構造的課題を理解する

MS Projectのカスタムフィールドは、内部的には以下のような構造になっています。

  • Text1: “プロジェクトA”
  • Number1: 100
  • Date1: 2023/12/31

外部システム(例えば、Pythonで動くAI解析ツールや、Reactで作られたダッシュボード)にとって、`Text1`が「プロジェクト名」なのか「担当者名」なのかは、プロジェクトファイルを開かない限り分かりません。

これを解決するのがJSON(JavaScript Object Notation)です。

{
  "TaskName": "設計フェーズ",
  "ProjectStatus": "進行中",
  "Priority": 1
}

このように、「フィールドのインデックス(Text1)」を「意味のあるキー(ProjectStatus)」に変換(シリアライズ)すること。これが、今回のミッションの核心です。

2. アーキテクチャの設計図:マッピング・ディクショナリ

いきなりコードを書くのは二流です。一流はまず、「どのフィールドが、どの名前になるのか」という設計図(マッピング)を定義します。

VBAには、キーと値をペアで保持できる`Scripting.Dictionary`という非常に強力なオブジェクトがあります。これを使って、「`Text1` は `Status` である」という定義を行います。

概念図

1. Source (MS Project): `Task.Text1` $\rightarrow$ `”完了”`
2. Mapping Layer: `Text1` $\rightarrow$ `”TaskStatus”`
3. Target (JSON): `{“TaskStatus”: “完了”}`

3. 実装:カスタムフィールドをJSONへエクスポートする

それでは、実際に動くコードを見ていきましょう。ここでは、タスクの情報を抽出し、JSON形式の文字列を生成するロジックを実装します。

※このコードを動かすには、VBAエディタの [ツール] $\rightarrow$ [参照設定] から 「Microsoft Scripting Runtime」 にチェックを入れてください。

Option Explicit

''' <summary>
''' タスクのカスタムフィールドをJSON形式にエクスポートする
''' </summary>
Public Sub ExportTasksToJson()
    Dim task As Task
    Dim jsonDict As Object
    Dim taskList As Object
    Dim mapping As Object
    Dim jsonString As String
    Dim i As Integer
    
    ' 1. マッピングの定義 (ここが設計の肝!)
    ' Text1 = Status, Text2 = Category, Number1 = CostIndex と定義
    Set mapping = CreateObject("Scripting.Dictionary")
    mapping.Add "Text1", "TaskStatus"
    mapping.Add "Text2", "TaskCategory"
    mapping.Add "Number1", "CostIndex"
    
    ' 2. JSON構造の構築用オブジェクト
    ' 本来はJSONライブラリを使うのがベストだが、今回は概念理解のため
    ' 文字列結合による簡易的なシリアライザを実装する
    Set taskList = CreateObject("Scripting.Dictionary")
    
    On Error Resume Next ' タスクが未完了(削除済み等)の場合のガード
    
    For Each task In ActiveProject.Tasks
        ' 有効なタスクのみ処理
        If Not task Is Nothing Then
            Dim taskData As String
            taskData = "{"
            
            ' マッピングに基づいてカスタムフィールドを走査
            Dim key As Variant
            Dim fieldName As String
            Dim fieldVal As Variant
            
            i = 0
            For Each key In mapping.Keys
                fieldName = mapping(key)
                ' フィールドの値を取得 (Text1, Text2... と動的に指定)
                fieldVal = GetFieldValue(task, key)
                
                ' JSONのプロパティを追加
                taskData = taskData & """" & fieldName & """: """ & CStr(fieldVal) & """"
                
                ' 最後の要素でなければカンマを打つ
                If i < mapping.Count - 1 Then taskData = taskData & ","
                i = i + 1
            Next key
            
            taskData = taskData & "}"
            
            ' タスクリストに蓄積(本来は配列やコレクションで管理)
            ' 今回は簡易的に、一つの大きな文字列として結合していく
            If jsonString = "" Then
                jsonString = "[" & taskData
            Else
                jsonString = jsonString & "," & taskData
            End If
        End If
    Next task
    
    jsonString = jsonString & "]"
    On Error GoTo 0
    
    ' 3. 結果の出力(イミディエイトウィンドウ)
    Debug.Print jsonString
    MsgBox "エクスポート完了!イミディエイトウィンドウを確認してください。", vbInformation
End Sub

''' <summary>
''' フィールド名を元に、動的にタスクのプロパティを取得するヘルパー関数
''' </summary>
Private Function GetFieldValue(targetTask As Task, fieldName As String) As Variant
    ' fieldName は "Text1", "Number1" などの形式を想定
    ' VBAのExecuteメソッド等を使う方法もあるが、シンプルにプロパティとして扱う
    On Error Resume Next
    Select Case Left(fieldName, 4)
        Case "Text"
            GetFieldValue = targetTask.Text & Mid(fieldName, 5) ' 実はText1はプロパティ名が特殊な場合がある
            ' Project VBAの仕様上、Text1は直接 .Text1 とは書けないため注意
            ' 以下の手法が最も安全
            GetFieldValue = CallByName(targetTask, fieldName, VbGet)
        Case "Num"
            GetFieldValue = CallByName(targetTask, fieldName, VbGet)
        Case "Date"
            GetFieldValue = CallByName(targetTask, fieldName, VbGet)
    End Select
    On Error GoTo 0
End Function

💡 ここが「プロ」の視点:`CallByName` の活用

コードの中で `CallByName` という関数を使いました。これは、「文字列で指定されたプロパティ名を使って、オブジェクトの値を動的に取得する」という魔法のような関数です。
`task.Text1` と書くと、`Text1` という名前を固定で扱うことになりますが、`CallByName(task, “Text1”, VbGet)` と書けば、変数を使って柔軟にアクセスできます。これが、拡張性の高いコードを書くための鍵です。

4. インポートの極意:外部データをMS Projectへ戻す

エクスポートができたら、次はインポートです。
JSONをパース(解析)して、MS Projectの適切なフィールドに値を書き戻します。インポート時に最も注意すべきは、「どのタスクに対して書き込むのか?」という識別子の特定です。

通常、`TaskName`(タスク名)だけでは不十分です。名前が重複する可能性があるからです。実務では、`Unique ID` をキーにすることをお勧めします。

''' <summary>
''' JSON形式のデータを解析し、カスタムフィールドに書き戻す(ロジックの雛形)
''' </summary>
Public Sub ImportFromJson(jsonInput As String)
    ' 注意: 本来はJSONパースライブラリ(VBA-JSON等)を使用することを強く推奨します
    ' ここでは、ロジックの流れを解説します
    
    Dim task As Task
    Dim targetID As Long
    Dim statusVal As String
    
    ' 1. JSONをパースしてループ処理(擬似コード)
    ' For Each item In parsedJson
    '    targetID = item("UniqueID")
    '    statusVal = item("TaskStatus")
    
    ' 2. 対象タスクを検索
    ' Set task = FindTaskByID(targetID)
    
    ' 3. 書き戻し
    ' If Not task Is Nothing Then
    '    task.Text1 = statusVal
    ' End If
    
    MsgBox "インポートのロジックを実行しました(デモ用)", vbInformation
End Sub

5. 陥りやすいエラーと、それを回避する「守りの設計」

この領域を扱う際、多くのエンジニアが以下の罠にハマります。

① データ型の不一致(Type Mismatch)

JSONでは `100`(数値)と `”100″`(文字列)は別物です。MS Projectの `Number1` に `”完了”` という文字列を流し込もうとすると、ランタイムエラーが発生します。
対策: 書き込み前に、必ず `IsNumeric` や `IsDate` を使って、フィールドの型とデータの整合性をチェックしてください。

② 存在しないフィールドへのアクセス

プロジェクトの設定によって、カスタムフィールドが有効になっていない場合があります。
対策: `On Error Resume Next` で強引に飛ばすのではなく、事前にフィールドの利用可能性をチェックするか、エラーハンドリングを厳格に行いましょう。

③ パフォーマンスの壁

タスクが数千件あるプロジェクトで、ループの中で一つずつオブジェクトを操作すると、処理が劇的に遅くなります。
対策: 画面更新を停止する `Application.ScreenUpdating = False` はもちろん、大量のデータを扱う場合は、一度配列(Array)にデータを格納してから、最後に一括で書き戻す手法を検討してください。

最後に:一歩先へ進むあなたへ

カスタムフィールドをJSONで制御できるようになると、MS Projectは単なる「スケジュール管理ツール」から、「巨大なデータソース」へと変貌します。

「マクロの記録」を卒業し、こうしたオブジェクトの構造やデータ変換のロジックを理解することは、エンジニアとしての視座を一段引き上げてくれます。最初は難しく感じるかもしれませんが、一つ一つの関数が「なぜ必要なのか」を考えながら進めてみてください。

ここをクリアすれば、Project VBAの基本はバッチリですよ。
さあ、新しい世界へ踏み出しましょう!

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