事務屋さんの備忘録

主にプログラミングのことを書いていきます。メモというか備忘録的な感じで。プログラミングといっても、私はプロのエンジニアでも本職のプログラマーでもありません。単なる事務職をやってるサラリーマンで、空いた時間にちょこちょこっとプログラミングしてる程度です。よってこのブログに記載したことが誤っていたり、もっとよい方法がある場合もあると思います。その場合には、ご指摘いただけると嬉しいです。また、このブログを読んで役に立った、なんて方がいらっしゃったら幸いですね。

VBAでXMLのパースを行う

VBAxmlファイル読み込み、Excelファイルに書き出します。

<?xml version="1.0" encoding="Shift_JIS"?>
<ROOT>
    <INFO>
        <DATE>2014/01/02</DATE>
        <CUSTOMER>サンプル会社</CUSTOMER>
    </INFO>
    <DATA>
        <PRODUCTINFO>
            <SERIALNO>0001</SERIALNO>
            <PRODUCTNAME>製品1</PRODUCTNAME>
            <PRICE>500</PRICE>
            <STOCK quantity="10" lineNumber="1">10</STOCK>
        </PRODUCTINFO>
        <PRODUCTINFO>
            <SERIALNO>0002</SERIALNO>
            <PRODUCTNAME>製品2</PRODUCTNAME>
            <PRICE>1000</PRICE>
            <STOCK quantity="20" lineNumber="2">20</STOCK>
        </PRODUCTINFO>
    </DATA>
</ROOT>
<?xml version="1.0" encoding="Shift_JIS"?>
<ROOT>
    <INFO>
        <DATE>2014/01/02</DATE>
        <CUSTOMER>サンプル会社</CUSTOMER>
    </INFO>
    <DATA>
        <PRODUCTINFO>
            <SERIALNO>0003</SERIALNO>
            <PRODUCTNAME>製品3</PRODUCTNAME>
            <PRICE>300</PRICE>
            <STOCK quantity="30" lineNumber="3">30</STOCK>
        </PRODUCTINFO>
        <PRODUCTINFO>
            <SERIALNO>0004</SERIALNO>
            <PRODUCTNAME>製品4</PRODUCTNAME>
            <PRICE>4000</PRICE>
            <STOCK quantity="40" lineNumber="4">40</STOCK>
        </PRODUCTINFO>
    </DATA>
</ROOT>
Option Explicit

Dim myFSO As New FileSystemObject   'FSO Microsoft Scripting Runtime を参照設定

Dim strPath       As String  'このマクロファイルのパス
Dim strExtName    As String  '拡張子
Dim strFileName() As String  '拡張子がxmlのファイル

Dim intCntF As Integer  'strFileName()の要素数
Dim intY    As Integer  '行方向カウンター
Dim intX    As Integer  '列方向カウンター
Dim i       As Integer  'For用

Sub Sample1()
    
    strPath = ThisWorkbook.Path
    
    intCntF = 0
    ReDim Preserve strFileName(intCntF)
    strFileName(intCntF) = Dir(strPath & "\*.xml")
    
    Do Until strFileName(intCntF) = ""
    
        'ファイルの拡張子を取得
        strExtName = myFSO.GetExtensionName(strPath & "\" & strFileName(intCntF))
        
        If LCase(strExtName) = "xml" Then
        
            intCntF = intCntF + 1
            ReDim Preserve strFileName(intCntF)
                   
        End If
    
        strFileName(intCntF) = Dir()
        
    Loop
    
    
    'Microsoft XML v6.0 を参照設定
    Dim XMLDocument As MSXML2.DOMDocument
    Dim xmlDate     As IXMLDOMNode
    Dim xmlCustomer As IXMLDOMNode
    Dim xmlDataNode As IXMLDOMNode

    'MSXMLオブジェクトを生成し、xmlファイルをロード
    Set XMLDocument = New MSXML2.DOMDocument
    
    'async = False → 読み込み終了後、次の処理をします(同期処理)
    'async = true →だと、読み込みが終わらなくても、次のステップへ(非同期処理)
    'VBAは非同期処理に対応していないので、async = Falseとします
    XMLDocument.async = False
    
    intY = 1
    For i = 0 To UBound(strFileName) - 1
        
        intX = 1  '1列目に戻します
        
        XMLDocument.Load (strPath & "\" & strFileName(i))
        
        If (XMLDocument.parseError.ErrorCode <> 0) Then 'ロード失敗
            
            Dim strMsg As String
            strMsg = XMLDocument.parseError.reason      'エラー内容を出力
            
            MsgBox "ロードに失敗しました・・・" & vbCrLf & vbCrLf & strMsg, vbCritical
            
            Exit Sub
        
        End If
    
        '<INFO>ノードの各情報を取得(検索指定)
        Set xmlDate = XMLDocument.SelectSingleNode("//ROOT/INFO/DATE")
        Set xmlCustomer = XMLDocument.SelectSingleNode("//ROOT/INFO/CUSTOMER")
        
        
        Cells(intY, intX) = xmlDate.Text       '<DATE>情報を出力
        intX = intX + 1
        
        Cells(intY, intX) = xmlCustomer.Text   '<CUSTOMER>情報を出力
        intX = intX + 1
        
        '<DATA>ノードデータを取得
        Set xmlDataNode = XMLDocument.SelectSingleNode("//ROOT/DATA")
    
        '<DATA>ノードの子要素をループで抽出
        Dim Node As IXMLDOMNode
        For Each Node In xmlDataNode.ChildNodes
    
            '<PRODUCTINFO>ノードの子要素を出力
            Cells(intY, intX) = Node.ChildNodes(0).Text  '<SERIALNO>情報を出力
            intX = intX + 1
            
            Cells(intY, intX) = Node.ChildNodes(1).Text  '<PRODUCTNAME>情報を出力
            intX = intX + 1
            
            Cells(intY, intX) = Node.ChildNodes(2).Text  '<PRICE>情報を出力
            intX = intX + 1
            
            Cells(intY, intX) = Node.ChildNodes(3).Text  '<STOCK>情報を出力
            intX = intX + 1
            
            
            '<STOCK quantity="10" lineNumber="1">
            Cells(intY, intX) = Node.ChildNodes(3).Attributes(0).Text  'quantity属性情報を出力
            intX = intX + 1
            
            Cells(intY, intX) = Node.ChildNodes(3).Attributes(1).Text  'lineNumber属性情報を出力
            intX = intX + 1
            
        Next
    
        '各オブジェクトの開放
        If Not xmlDate Is Nothing Then Set xmlDate = Nothing
        If Not xmlCustomer Is Nothing Then Set xmlCustomer = Nothing
        If Not xmlDataNode Is Nothing Then Set xmlDataNode = Nothing
        
        
        intY = intY + 1   '行を下げます
        
    Next
    
    'オブジェクトの開放
    If Not XMLDocument Is Nothing Then Set XMLDocument = Nothing
    
    MsgBox "パース完了!"
    
    End

End Sub