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