0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Tableauワークブック解析マクロ

Last updated at Posted at 2025-06-17

Tableauのワークブック(TWBファイル)について、ワークシートごとのレイアウトの内容と、データソースごとの項目の一覧を抽出できるマクロです。

' カラム名を整形する関数
Private Function FormatColumnName(inputStr As String) As String
    Dim parts() As String
    Dim secondPart As String
    
    ' 「.」で分割
    parts = Split(inputStr, ".")
    
    ' 分割した要素が存在する場合
    If UBound(parts) >= 0 Then
        ' 最後の要素を取得
        secondPart = parts(UBound(parts))
        
        ' 「:」で分割
        Dim colonParts() As String
        colonParts = Split(secondPart, ":")
        
        ' 「:」で分割した2要素目を返却
        If UBound(colonParts) >= 1 Then
            FormatColumnName = Replace(Replace(colonParts(1), "[", ""), "]", "")
        Else
            ' 「:」がない場合は「[」と「]」を除去して返却
            FormatColumnName = Replace(Replace(secondPart, "[", ""), "]", "")
        End If
    Else
        ' 「.」で分割できない場合は「[」と「]」を除去して返却
        FormatColumnName = Replace(Replace(inputStr, "[", ""), "]", "")
    End If
End Function

Sub ExtractWorksheetNames()
    Dim xmlDoc As Object
    Dim worksheetNodes As Object
    Dim worksheetNode As Object
    Dim ws As Worksheet
    Dim outputSheet As Worksheet
    Dim i As Long
    
    ' 「メイン」シートを参照
    Set ws = ThisWorkbook.Worksheets("メイン")
    
    ' XMLファイルのパスを取得
    Dim xmlFilePath As String
    xmlFilePath = ws.Range("C2").Value
    
    ' XMLドキュメントを作成
    Set xmlDoc = CreateObject("MSXML2.DOMDocument")
    
    ' ファイルが存在するか確認
    If Dir(xmlFilePath) = "" Then
        MsgBox "指定されたXMLファイルが見つかりません: " & xmlFilePath, vbCritical
        Exit Sub
    End If
    
    ' XMLファイルを読み込む
    xmlDoc.Load (xmlFilePath)
    
    ' <worksheet>ノードを取得
    Set worksheetNodes = xmlDoc.getElementsByTagName("worksheet")
    
    ' 出力用のシートを作成(既存の場合は削除)
    On Error Resume Next
    Application.DisplayAlerts = False
    ThisWorkbook.Worksheets("ワークシート解析結果").Delete
    ThisWorkbook.Worksheets("データソース解析結果").Delete
    Application.DisplayAlerts = True
    On Error GoTo 0
    
    Set outputSheet = ThisWorkbook.Worksheets.Add(After:=ThisWorkbook.Worksheets(ThisWorkbook.Worksheets.Count))
    outputSheet.Name = "ワークシート解析結果"
    
    ' ヘッダー追加
    outputSheet.Range("A1").Value = "ワークシート名"
    outputSheet.Range("B1").Value = "カラム名"
    outputSheet.Range("C1").Value = "配置場所"
    outputSheet.Range("D1").Value = "マーク種類"
    
    ' ワークシートごとにループ
    Dim outputRow As Long
    outputRow = 2
    
    For i = 0 To worksheetNodes.Length - 1
        Set worksheetNode = worksheetNodes(i)
        Dim worksheetName As String
        worksheetName = worksheetNode.getAttribute("name")
        
        ' <table>ノードを取得
        Dim tableNodes As Object
        Set tableNodes = worksheetNode.selectNodes("table")
        
        If tableNodes.Length > 0 Then
            Dim tableNode As Object
            Set tableNode = tableNodes(0)
            
            ' <view>ノードを取得
            Dim viewNodes As Object
            Set viewNodes = tableNode.selectNodes("view")
            
            If viewNodes.Length > 0 Then
                Dim viewNode As Object
                Set viewNode = viewNodes(0)
                
                ' <filter>ノードをすべて取得
                Dim filterNodes As Object
                Set filterNodes = viewNode.selectNodes("filter")
                
                ' フィルターノードをループ
                Dim filterNode As Object
                For Each filterNode In filterNodes
                    Dim filterColumnAttribute As String
                    filterColumnAttribute = filterNode.getAttribute("column")
                    
                    ' カラム属性がある場合のみ出力
                    If filterColumnAttribute <> "" Then
                        outputSheet.Cells(outputRow, 1).Value = worksheetName
                        outputSheet.Cells(outputRow, 2).Value = FormatColumnName(filterColumnAttribute)
                        outputSheet.Cells(outputRow, 3).Value = "フィルター"
                        outputSheet.Cells(outputRow, 4).Value = ""
                        outputRow = outputRow + 1
                    End If
                Next filterNode
            End If
            
            ' <panes>ノードを取得
            Dim panesNodes As Object
            Set panesNodes = tableNode.selectNodes("panes")
            
            If panesNodes.Length > 0 Then
                Dim panesNode As Object
                Set panesNode = panesNodes(0)
                
                ' <pane>ノードを取得
                Dim paneNodes As Object
                Set paneNodes = panesNode.selectNodes("pane")
                
                If paneNodes.Length > 0 Then
                    Dim paneNode As Object
                    Set paneNode = paneNodes(0)
                    
                    ' <encodings>ノードを取得
                    Dim encodingsNodes As Object
                    Set encodingsNodes = paneNode.selectNodes("encodings")
                    
                    If encodingsNodes.Length > 0 Then
                        Dim encodingsNode As Object
                        Set encodingsNode = encodingsNodes(0)
                        
                        ' <encodings>の子要素をループ
                        Dim childNode As Object
                        For Each childNode In encodingsNode.childNodes
                            ' 要素ノードのみ処理
                            If childNode.nodeType = 1 Then  ' 要素ノード
                                Dim columnAttribute As String
                                columnAttribute = childNode.getAttribute("column")
                                
                                ' カラム属性がある場合のみ出力
                                If columnAttribute <> "" Then
                                    outputSheet.Cells(outputRow, 1).Value = worksheetName
                                    outputSheet.Cells(outputRow, 2).Value = FormatColumnName(columnAttribute)
                                    outputSheet.Cells(outputRow, 3).Value = "マーク"
                                    outputSheet.Cells(outputRow, 4).Value = childNode.nodeName
                                    outputRow = outputRow + 1
                                End If
                            End If
                        Next childNode
                    End If
                End If
            End If
            
            ' <rows>ノードを取得
            Dim rowsNodes As Object
            Set rowsNodes = tableNode.selectNodes("rows")
            
            If rowsNodes.Length > 0 Then
                Dim rowsNode As Object
                Set rowsNode = rowsNodes(0)
                
                ' innerTextを取得
                Dim rowsText As String
                rowsText = rowsNode.Text
                
                ' 「(」と「)」を除去
                rowsText = Replace(Replace(rowsText, "(", ""), ")", "")
                
                ' 「/」で分割
                Dim rowParts() As String
                rowParts = Split(rowsText, "/")
                
                ' 分割した要素数分ループ
                Dim j As Long
                For j = 0 To UBound(rowParts)
                    outputSheet.Cells(outputRow, 1).Value = worksheetName
                    outputSheet.Cells(outputRow, 2).Value = FormatColumnName(rowParts(j))
                    outputSheet.Cells(outputRow, 3).Value = "行シェルフ"
                    outputSheet.Cells(outputRow, 4).Value = ""
                    outputRow = outputRow + 1
                Next j
            End If
            
            ' <cols>ノードを取得
            Dim colsNodes As Object
            Set colsNodes = tableNode.selectNodes("cols")
            
            If colsNodes.Length > 0 Then
                Dim colsNode As Object
                Set colsNode = colsNodes(0)
                
                ' innerTextを取得
                Dim colsText As String
                colsText = colsNode.Text
                
                ' 「(」と「)」を除去
                colsText = Replace(Replace(colsText, "(", ""), ")", "")
                
                ' 「/」で分割
                Dim colParts() As String
                colParts = Split(colsText, "/")
                
                ' 分割した要素数分ループ
                Dim k As Long
                For k = 0 To UBound(colParts)
                    outputSheet.Cells(outputRow, 1).Value = worksheetName
                    outputSheet.Cells(outputRow, 2).Value = FormatColumnName(colParts(k))
                    outputSheet.Cells(outputRow, 3).Value = "列シェルフ"
                    outputSheet.Cells(outputRow, 4).Value = ""
                    outputRow = outputRow + 1
                Next k
            End If
        End If
    Next i
    
    ' <datasources>ノードを取得
    Dim datasourcesNodes As Object
    Set datasourcesNodes = xmlDoc.getElementsByTagName("datasources")
    
    If datasourcesNodes.Length > 0 Then
        Dim datasourcesNode As Object
        Set datasourcesNode = datasourcesNodes(0)
        
        ' <datasource>ノードを取得
        Dim datasourceNodes As Object
        Set datasourceNodes = datasourcesNode.selectNodes("datasource")
        
        ' 出力用のシートを作成(既存の場合は削除)
        On Error Resume Next
        Application.DisplayAlerts = False
        ThisWorkbook.Worksheets("データソース解析結果").Delete
        Application.DisplayAlerts = True
        On Error GoTo 0
        
        Set outputSheet = ThisWorkbook.Worksheets.Add(After:=ThisWorkbook.Worksheets(ThisWorkbook.Worksheets.Count))
        outputSheet.Name = "データソース解析結果"
        
        ' ヘッダー追加
        outputSheet.Range("A1").Value = "データソース名"
        outputSheet.Range("B1").Value = "カラム名"
        outputSheet.Range("C1").Value = "カラム名(計算フィールド)"
        outputSheet.Range("D1").Value = "計算式"
        
        ' データソース出力の開始行をリセット
        outputRow = 2
        
        ' データソースごとにループ
        Dim datasourceNode As Object
        For Each datasourceNode In datasourceNodes
            Dim datasourceName As String
            
            ' caption属性を取得(なければname属性)
            If datasourceNode.getAttribute("caption") <> "" Then
                datasourceName = Replace(Replace(datasourceNode.getAttribute("caption"), "[", ""), "]", "")
            Else
                datasourceName = Replace(Replace(datasourceNode.getAttribute("name"), "[", ""), "]", "")
            End If
            
            ' <column>ノードを取得
            Dim columnNodes As Object
            Set columnNodes = datasourceNode.selectNodes("column")
            
            ' カラムごとにループ
            Dim columnNode As Object
            For Each columnNode In columnNodes
                Dim columnName As String
                Dim calculatedColumnName As String
                Dim calculationFormula As String
                
                ' caption属性がない場合はname属性を使用
                If columnNode.getAttribute("caption") <> "" Then
                    columnName = columnNode.getAttribute("caption")
                Else
                    columnName = Replace(Replace(columnNode.getAttribute("name"), "[", ""), "]", "")
                End If
                
                ' name属性を確認
                Dim columnNameAttribute As String
                columnNameAttribute = columnNode.getAttribute("name")
                
                ' 初期化
                calculationFormula = ""
                calculatedColumnName = ""
                
                ' 「Calculation_」から始まる場合
                If Left(Replace(Replace(columnNameAttribute, "[", ""), "]", ""), 12) = "Calculation_" Then
                    calculatedColumnName = Replace(Replace(columnNameAttribute, "[", ""), "]", "")
                    
                    ' <calculation>要素のformula属性を取得
                    Dim calculationNode As Object
                    Set calculationNode = columnNode.selectSingleNode("calculation")
                    If Not calculationNode Is Nothing Then
                        calculationFormula = calculationNode.getAttribute("formula")
                    End If
                End If
                
                ' 出力
                outputSheet.Cells(outputRow, 1).Value = datasourceName
                outputSheet.Cells(outputRow, 2).Value = columnName
                outputSheet.Cells(outputRow, 3).Value = calculatedColumnName
                outputSheet.Cells(outputRow, 4).Value = calculationFormula
                outputRow = outputRow + 1
            Next columnNode
        Next datasourceNode
    End If
    
    MsgBox "ワークブックの解析が完了しました。", vbInformation
End Sub
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?