VBAからGDI+を使う資料集
inet上の達人の方々から御教示いただいたコードを少しアレンジさせてもらっています(切り貼りとも言います)。
  1. ホーム
  2. Other
  3. validation2


動的な入力規則生成をMSXML DOMでやってみた Part2

調子に乗って多段階をやってみました。汎用化が楽そうなのでXPathを使っていますが、SelectSingleNode等は、MSXMLの方言の様ですね。試験をしたのは5段階までです。5^5=3125個のDOMへの読込に0.数秒かかりますが、一旦オブジェクトを生成した後の読み出しは全くストレスフリーです。
WorksheetのA~E列に順次生成させていますので、エラー処理とか面倒ですが、UserFormのComboBox等に使用すれば結構実用的かもしれません。


☆入力規則生成用のデータ(Sheets("Sheet1"))
L1	L2	L3 	L4	L5
A	A1	A11	A111	A1111
A	A1	A11	A111	A1112
(以下略)

☆標準モジュール
'汎用化したので、コードは短くなっています。
'Microsoft XML V3.0に参照設定
Public oXMLDom As DOMDocument30
Public myColumnCount As Long

Public Sub setDOM()
  Dim i As Long, j As Long, k As Long
  Dim myXPath As String
  Dim targetRange As Range
  Dim buf As Variant
  Dim root As IXMLDOMElement
    
  Set oXMLDom = New DOMDocument30
  '初期設定
  settingDOM oXMLDom
  setInfo oXMLDom, "xml test"
  'ワークシートから絞り込み選択用リスト取得 Variant配列に収納
  Set targetRange = ThisWorkbook.Sheets("Sheet1").Range("A1").CurrentRegion
  Set targetRange = Intersect(targetRange, targetRange.Offset(1, 0))
  buf = targetRange.Value
  Set root = oXMLDom.createElement("root")
  oXMLDom.appendChild root
  myColumnCount = UBound(buf, 1)
  
  For i = 1 To UBound(buf, 2)
    Call addElement(root, i, buf)
  Next i
'  Debug.Print oXMLDom.XML
End Sub
  
Sub addElement(root As IXMLDOMElement, level As Long, buf As Variant)
  Dim i As Long, j As Long
  Dim parentElement As IXMLDOMElement
  Dim newElement As IXMLDOMElement
  Dim myXPath As String
  Dim retNode As IXMLDOMNodeList
  
  For i = 1 To UBound(buf, 1)
    myXPath = "/" & root.nodeName
    For j = 1 To level - 1
      If level > 1 Then myXPath = myXPath & "/" & buf(i, j)
    Next j
    
    Set parentElement = root.SelectSingleNode(myXPath)
    Set retNode = root.SelectNodes(myXPath & "/" & buf(i, level))
    If retNode.Length = 0 Then
      Set newElement = oXMLDom.createElement(buf(i, level))
      parentElement.appendChild newElement
    End If
  Next i
End Sub

'MSXMLDOMの設定
Private Sub settingDOM(ByRef dom As DOMDocument30)
  With dom
    .async = False
    .validateOnParse = False
    .resolveExternals = False
    .preserveWhiteSpace = True
    .setProperty "SelectionLanguage", "XPath"
  End With
End Sub

'XMLのヘッダー?の部分を設定
Private Sub setInfo(ByRef dom As DOMDocument30, comment As String)
  Dim node As IXMLDOMNode
  
  Set node = dom.createProcessingInstruction("xml", "version=""1.0"" encoding=""Shift_JIS""")
  dom.appendChild node
  Set node = Nothing
  Set node = dom.createComment(comment)
  dom.appendChild node
  Set node = Nothing
End Sub

☆ワークシートモジュール
A→B→C→D→E列にWorksheet_SelectionChangeのイベントにより動的に入力規則を生成します
Private Sub Worksheet_SelectionChange(ByVal target As Range)
  Dim Dummy As Range

  If oXMLDom Is Nothing Then setDOM
  If target.Cells.Count > 1 Then Exit Sub
  If target.Column > myColumnCount Then Exit Sub
  If target.Column > 1 Then
    On Error Resume Next
    Set Dummy = Intersect(target.Offset(0, -1), target.Offset(0, -1).SpecialCells(xlCellTypeAllValidation))
    On Error GoTo 0
    If Dummy Is Nothing Then Exit Sub
  End If
  setValidation target
End Sub

Private Sub setValidation(target As Range)
  Dim i As Long, j As Long
  Dim myXPath As String
  Dim root As IXMLDOMElement
  Dim retNode As IXMLDOMNodeList
  Dim strValidation As String

  Set root = oXMLDom.DocumentElement
  
  On Error GoTo errorHandle
  If target.Column = 1 Then
    Set retNode = root.ChildNodes
  Else
    myXPath = "/" & root.nodeName
    For j = target.Column - 1 To 1 Step -1
      myXPath = myXPath & "/" & target.Offset(0, -1 * j)
    Next j
    Set retNode = root.SelectSingleNode(myXPath).ChildNodes
  End If
  If retNode Is Nothing Then Exit Sub
  For i = 0 To retNode.Length - 1
    If strValidation = "" Then
      strValidation = retNode(i).nodeName
    Else
      strValidation = strValidation & "," & retNode(i).nodeName
    End If
    setvalidationSub target, strValidation
  Next i
errorHandle:
End Sub

Private Sub setvalidationSub(target As Range, strValidation As String)
    With target.Validation
        .Delete
        .Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:= _
        xlBetween, Formula1:=strValidation
    End With
End Sub