XMLは便利だけどオブジェクトが沢山あって面倒
なので汎用的なクラスを作ってみる
XMLUtilClass.cls
VERSION 1.0 CLASS
BEGIN
MultiUse = -1 'True
END
Attribute VB_Name = "XMLUtilClass"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
Option Explicit
Private g_XMLDocument As New DOMDocument50
Private g_currentNode As IXMLDOMNode
Private g_xml_path As String
Private g_xpath_node As String
Private g_xml_selection As IXMLDOMSelection
'attribute のセット
Public Sub setAttributeElement(ele As IXMLDOMElement, name As String, value As String)
Dim att As MSXML2.IXMLDOMAttribute
Set att = g_XMLDocument.createAttribute(name)
att.Text = value
ele.setAttributeNode att
Set att = Nothing
End Sub
'attribute のセット
Public Sub setAttributeEx(name As String, value As String)
Call setAttribute(g_currentNode, name, value)
End Sub
'attribute のセット(旧版)
Private Sub setAttribute_OLD(node As IXMLDOMNode, name As String, value As String)
'attributeがある場合は上書き
If node Is Nothing Then Exit Sub
Dim i As Integer
Dim n As IXMLDOMNode
For i = 0 To node.Attributes.Length - 1
If name = node.Attributes(i).baseName Then
node.Attributes(i).Text = value
Exit Sub
End If
Next
'無い場合は作成
Call addAttribute(node, name, value)
End Sub
'attribute のセット
Public Sub setAttribute(node As IXMLDOMNode, name As String, value As String)
Dim n As IXMLDOMNode
'attributeがある場合は上書き
If node Is Nothing Then Exit Sub
Set n = node.Attributes.getNamedItem(name)
If n Is Nothing Then
'無い場合は作成
Call addAttribute(node, name, value)
Else
n.Text = value
End If
Set n = Nothing
End Sub
'attribute の追加
Public Sub addAttribute(node As IXMLDOMNode, name As String, value As String)
If node Is Nothing Then Exit Sub
Dim att As IXMLDOMNode
Set att = g_XMLDocument.createAttribute(name)
att.Text = value
Dim dmy As Object
Set dmy = node.Attributes.setNamedItem(att)
Set att = Nothing
Set dmy = Nothing
End Sub
'attribute の追加
Public Sub addAttributeEx(name As String, value As String)
Call addAttribute(g_currentNode, name, value)
End Sub
'attribute の削除
Public Sub removeAttributes(node As IXMLDOMNode, name As String)
If node Is Nothing Then Exit Sub
node.Attributes.removeNamedItem (name)
End Sub
'attribute の削除
Public Sub removeAttributesEx(name As String)
Call removeAttributes(g_currentNode, name)
End Sub
'attribute の数
Public Static Function sizeAttributes(node As IXMLDOMNode) As Long
sizeAttributes = 0
If node Is Nothing Then Exit Function
sizeAttributes = node.Attributes.Length
End Function
'attribute の数
Public Static Function sizeAttributesEx() As Long
sizeAttributesEx = sizeAttributes(g_currentNode)
End Function
'attribute が存在するか(旧版)
Private Static Function containsKeyAttribute_OLD(node As IXMLDOMNode, name As String) As Boolean
containsKeyAttribute_OLD = False
If node Is Nothing Then Exit Function
Dim i As Integer
For i = 0 To node.Attributes.Length - 1
If name = node.Attributes(i).baseName Then
containsKeyAttribute_OLD = True
Exit Function
End If
Next
End Function
'attribute が存在するか
Public Static Function containsKeyAttribute(node As IXMLDOMNode, name As String) As Boolean
containsKeyAttribute = False
If node Is Nothing Then Exit Function
containsKeyAttribute = (Not node.Attributes.getNamedItem(name) Is Nothing)
End Function
'attribute が存在するか
Public Function containsKeyAttributeEx(name As String) As String
containsKeyAttributeEx = containsKeyAttribute(g_currentNode, name)
End Function
'attribute のゲット
Public Static Function getAttributeValue(node As IXMLDOMNode, name As String) As String
Dim n As IXMLDOMNode
Dim s As String
If node Is Nothing Then Exit Function
Set n = node.Attributes.getNamedItem(name)
If n Is Nothing Then
s = ""
Else
s = n.Text
End If
Set n = Nothing
getAttributeValue = s
End Function
'attribute のゲット(旧版)
Public Static Function getAttributeValue_OLD(node As IXMLDOMNode, name As String) As String
If node Is Nothing Then Exit Function
Dim i As Integer
For i = 0 To node.Attributes.Length - 1
If name = node.Attributes(i).baseName Then
getAttributeValue_OLD = node.Attributes(i).Text
Exit Function
End If
Next
End Function
'attribute のゲット
Public Function getAttributeValueEx(name As String) As String
getAttributeValueEx = getAttributeValue(g_currentNode, name)
End Function
'attributeの値のゲット(名)
Public Function getAttributeNames(node As IXMLDOMNode) As String()
Dim ret() As String
If node Is Nothing Then Exit Function
Dim i As Integer
For i = 0 To node.Attributes.Length - 1
ReDim Preserve ret(i)
ret(i) = node.Attributes(i).baseName
Next
getAttributeNames = ret
End Function
'attributeの値のゲット(名)
Public Function getAttributeNamesEx() As String()
getAttributeNamesEx = getAttributeNames(g_currentNode)
End Function
'attributeの値のゲット(配列)
Public Function getAttributeValues(node As IXMLDOMNode) As String()
Dim ret() As String
If node Is Nothing Then Exit Function
Dim i As Integer
For i = 0 To node.Attributes.Length - 1
ReDim Preserve ret(i)
ret(i) = node.Attributes(i).Text
Next
getAttributeValues = ret
End Function
'attributeの値のゲット(配列)
Public Function getAttributeValuesEx() As String()
getAttributeValuesEx = getAttributeValues(g_currentNode)
End Function
'XMLファイルのロード
Public Sub loadXML(x_xml_path As String)
g_xml_path = x_xml_path
Set g_XMLDocument = New DOMDocument50
g_XMLDocument.async = False
g_XMLDocument.load (x_xml_path)
If g_XMLDocument.parsed = False Then
MsgBox "ファイル形式がXMLでありません。"
End If
'カレントノードにセット
Set g_currentNode = g_XMLDocument
End Sub
'XMLを新規作成する
Public Function createNewXML()
Dim s As String
s = "<?xml version=""1.0"" encoding=""UTF-8""?>"
g_XMLDocument.loadXML s
'カレントノードにセット
Set g_currentNode = g_XMLDocument
End Function
'XMLファイルのセーブ
Public Sub save(x_path)
If IsNull(x_path) = True Or x_path = "" Then
x_path = g_xml_path
End If
g_XMLDocument.save x_path
End Sub
'XMLDocumentからXPathによりノードを取得し、カレントノードに登録する
'状況に応じてgetSelectionNodeと使い分けると便利
Public Function getNode(x_xpath As String) As IXMLDOMNode
Set g_xml_selection = g_XMLDocument.selectNodes(x_xpath)
Set g_currentNode = g_xml_selection.NextNode
Set getNode = g_currentNode
End Function
'カレントノードを取得する
Public Function getCurrentNode() As IXMLDOMNode
Set getCurrentNode = g_currentNode
End Function
'XMLDocumentからXPathによりセレクションノードを取得し、クラスのメンバにもセットする
'状況に応じてgetNodeと使い分けると便利
'※セレクションに移動したくない場合等に使用
Public Function getSelectionNode(x_xpath As String) As IXMLDOMSelection
Set g_xml_selection = g_XMLDocument.selectNodes(x_xpath)
Set getSelectionNode = g_xml_selection
End Function
'セレクションノードをクラスのメンバにセットする
Public Sub setSelectionNode(x_xml_selection As IXMLDOMSelection)
Set g_xml_selection = x_xml_selection
End Sub
'次のノードを取得し、カレントノードに登録する
Public Function getNextNode() As IXMLDOMNode
Set g_currentNode = g_xml_selection.NextNode
Set getNextNode = g_currentNode
End Function
'ノードをカレントノードにセットする
Public Sub setNode(x_node As IXMLDOMNode)
Set g_currentNode = x_node
End Sub
'カレントノードにエレメントを追加&移動(子ノードを追加)
Public Function addElement(x_element_name As String)
Dim xml_element As IXMLDOMElement
Set xml_element = g_XMLDocument.createElement(x_element_name)
g_currentNode.appendChild xml_element
Set g_currentNode = xml_element
Set xml_element = Nothing
End Function
'カレントノード(エレメント)に値を記述する
Public Function setNodeValue(x_value As String)
g_currentNode.Text = x_value
End Function
'カレントノード(エレメント)の値を取得する
Public Function getNodeValueEx() As String
If Not g_currentNode Is Nothing Then
getNodeValueEx = g_currentNode.Text
End If
End Function
'カレントノード(エレメント)の値を取得する
Public Function getNodeValue(node As IXMLDOMNode) As String
If Not node Is Nothing Then
getNodeValue = node.Text
End If
End Function
'親ノードを取得&移動
Public Function getParentNode() As IXMLDOMNode
Set g_currentNode = g_currentNode.parentNode
Set getParentNode = g_currentNode
End Function
'カレントノードを削除して親ノードへ移動する
Public Function removeNode()
If g_currentNode Is Nothing Then
Exit Function
End If
Dim parentNode As IXMLDOMNode
Set parentNode = g_currentNode.parentNode
Call parentNode.removeChild(g_currentNode)
Set g_currentNode = parentNode
Set parentNode = Nothing
End Function
'子ノードを取得
Public Function getChildNodes() As IXMLDOMNodeList
If g_currentNode Is Nothing Then
Exit Function
End If
Set getChildNodes = g_currentNode.childNodes
End Function
Public Function getXML() As String
getXML = g_XMLDocument.xml
End Function
'ターミネイト
Private Sub Class_Terminate()
Set g_XMLDocument = Nothing
Set g_currentNode = Nothing
Set g_xml_selection = Nothing
End Sub
'属性をmapに格納します
Public Function getAttributeMapEx() As XmlCustomMap
Set getAttributeMapEx = getAttributeMap(g_currentNode)
End Function
'属性をmapに格納します
Public Function getAttributeMap(node As IXMLDOMNode) As XmlCustomMap
Dim l_att() As String
Dim l_map As New XmlCustomMap
Dim i As Integer
If Not node Is Nothing Then
l_att = getAttributeNames(node)
For i = 0 To UBound(l_att)
Call l_map.putValue(l_att(i), getAttributeValue(node, l_att(i)))
Next
End If
Set getAttributeMap = l_map
End Function
Sub xml_test()
Dim cls As New XMLUtilClass
'XML新規作成
cls.createNewXML
'要素追加&移動
Call cls.addElement("testelement1")
'要素追加&移動
Call cls.addElement("testelement2")
'要素の値をセット
Call cls.setNodeValue("nodevalue1")
'属性追加
Call cls.setAttributeEx("testname", "testvalue")
Call cls.setAttributeEx("testname2", "5")
'要素親へ移動
Call cls.getParentNode
'要素追加&移動
Call cls.addElement("testelement2")
'要素の値をセット
Call cls.setNodeValue("nodevalue2")
'属性追加
Call cls.setAttributeEx("testname", "testvalue")
Call cls.setAttributeEx("testname2", "10")
'XMLを保存
cls.save ("C:\temp\test.xml")
'開放
Set cls = Nothing
MsgBox "おわり"
End Sub
結果(test.xml)
<testelement1> <testelement2 testname="testvalue" testname2="5">nodevalue1</testelement2> <testelement2 testname="testvalue" testname2="10">nodevalue2</testelement2> </testelement1>
Sub xml_test2()
Dim cls As New XMLUtilClass
Dim n() As String
Dim v() As String
Dim i As Integer
'XMLファイルをロード
cls.loadXML ("C:\temp\test.xml")
'XPathからセレクションノードを取得
cls.getSelectionNode ("testelement1/testelement2")
'全取得ノード分ループ
Do While (Not cls.getNextNode() Is Nothing)
'属性を全て取得
n = cls.getAttributeNamesEx
v = cls.getAttributeValuesEx
For i = 0 To UBound(n)
Debug.Print n(i) & ":" & v(i)
Next
Loop
Set cls = Nothing
MsgBox "おわり"
End Sub
結果
testname:testvalue testname2:5 testname:testvalue testname2:10
Sub xml_test3()
Dim cls As New XMLUtilClass
'XMLファイルをロード
cls.loadXML ("C:\temp\test.xml")
'XPathからセレクションノードを取得
cls.getSelectionNode ("//testelement2[number(@testname2)>8 and contains(@testname,'value')]")
'全取得ノード分ループ
Do While (Not cls.getNextNode() Is Nothing)
'属性を取得
Debug.Print "testname:" & cls.getAttributeValueEx("testname") & " testname2:" & cls.getAttributeValueEx("testname2")
Loop
Set cls = Nothing
MsgBox "おわり"
End Sub
結果
testname:testvalue testname2:10
Sub xml_test4_3()
Dim cls As New XMLUtilClass
'XMLファイルをロード
cls.loadXML ("C:\temp\test.xml")
'XPathからセレクションノードを取得
cls.getSelectionNode ("testelement1")
Do While (Not cls.getNextNode() Is Nothing)
Dim childNodelist As IXMLDOMNodeList
Dim childNode As IXMLDOMNode
'子ノードリストを取得
Set childNodelist = cls.getChildNodes
'子ノードを全て取得
For Each childNode In childNodelist
'属性を取得
Debug.Print " testname1:" & cls.getAttributeValue(childNode, "testname") & _
" testname2:" & cls.getAttributeValue(childNode, "testname2") & _
" NodeValue:" & cls.getNodeValue(childNode)
Next
Set childNodelist = Nothing
Set childNode = Nothing
Loop
Set cls = Nothing
MsgBox "おわり"
End Sub
結果
testname1:testvaluetestname2:5 nodevalue1 testname1:testvaluetestname2:10 nodevalue2