Search code examples
xmlvbaexcelvbscriptxmldom

Editing All Text Nodes of XML DOM using Excel VBA


I am trying to Edit a XML DOM file using Excel VBA, but facing issues reaching beyond level 1 nodes. My requirement is to Modify all (and only) Text nodes but the script I wrote modifies all level 1 nodes.

Please suggest Code Modifications.

Input XML:

<?xml version="1.0" encoding="UTF-8"?>
<Envelope>
    <Body>
        <Request>
            <individual>
                <hasName>
                    <firstName>ABC</firstName>
                    <lastName>DEF</lastName>
                </hasName>
                <birthDate>2015-01-10</birthDate>
                <hasContact>
                    <type>Mobile</type>
                    <phoneAddress>
                        <countryCode>02</countryCode>
                        <localNumber>12345678</localNumber>
                    </phoneAddress>
                </hasContact>
            </individual>
        </Request>
    </Body>
</Envelope>

Excel VB Script:

Option Explicit
Sub Test()
Dim xmlDoc
Dim colNodes
Dim objNode
Dim objNodesParam

Set xmlDoc = CreateObject ("Microsoft.XMLDOM")
xmlDoc.Async = "False"
xmlDoc.Load("H:\Desktop\Request.xml")
Set colNodes = xmlDoc.SelectNodes ("/Envelope/Body/Request/individual/*")

For Each objNode In colNodes
objNodeParam = "{{" & objNode.nodeName & "}}"
objNode.Text = objNodeParam
Next

xmlDoc.Save "H:\Desktop\Request.xml"

End Sub

Actual Output of Above Script:

  <?xml version="1.0" encoding="UTF-8"?>
  <Envelope>
    <Body>
        <Request>
            <individual>
                <hasName>{{hasName}}</hasName>
                <birthDate>{{birthDate}}</birthDate>
                <hasContact>{{hasContact}}</hasContact>
            </individual>
        </Request>
    </Body>
</Envelope>

Expected Output:

<?xml version="1.0" encoding="UTF-8"?>
<Envelope>
    <Body>
        <Request>
            <individual>
                <hasName>
                    <firstName>{{firstName}}</firstName>
                    <lastName>{{lastName}}</lastName>
                </hasName>
                <birthDate>{{birthDate}}</birthDate>
                <hasContact>
                    <type>{{type}}</type>
                    <phoneAddress>
                        <countryCode>{{countryCode}}</countryCode>
                        <localNumber>{{localNumber}}</localNumber>
                    </phoneAddress>
                </hasContact>
            </individual>
        </Request>
    </Body>
</Envelope>

Solution

  • For background see here. You need a recursive approach:

    Option Explicit
    
    Dim oFS    : Set oFS  = CreateObject("Scripting.FileSystemObject")
    Dim sFSpec : sFSpec   = oFS.GetAbsolutePathName("..\data\33921005.xml")
    Dim oXML   : Set oXML = CreateObject("Msxml2.DOMDocument.6.0")
    oXML.load sFSpec
    If 0 = oXML.parseError Then
       recursiveTraversal oXML.documentElement, 0
       WScript.Echo "==============="
       WScript.Echo oXML.xml
    Else
       WScript.Echo objMSXML.parseError.reason
    End If
    
    Sub recursiveTraversal(oElm, nIndent)
      If oElm.nodeType = 3 Then
         WScript.Echo Space(nIndent), oElm.text
         oElm.text = "{{" & oElm.parentNode.tagName & "}}"
      Else
         WScript.Echo Space(nIndent), oElm.tagName
         If 0 < oElm.childNodes.length Then
            Dim oChild
            For Each oChild In oElm.childNodes
                recursiveTraversal oChild, nIndent + 2
            Next
         End If
      End If
    End Sub
    

    output:

    cscript 33921005.vbs
     Envelope
       Body
         Request
           individual
             hasName
               firstName
                 ABC
               lastName
                 DEF
             birthDate
               2015-01-10
             hasContact
               type
                 Mobile
               phoneAddress
                 countryCode
                   02
                 localNumber
                   12345678
    ===============
    <?xml version="1.0"?>
    <Envelope>
            <Body>
                    <Request>
                            <individual>
                                    <hasName>
                                            <firstName>{{firstName}}</firstName>
                                            <lastName>{{lastName}}</lastName>
                                    </hasName>
                                    <birthDate>{{birthDate}}</birthDate>
                                    <hasContact>
                                            <type>{{type}}</type>
                                            <phoneAddress>
                                                    <countryCode>{{countryCode}}</countryCode>
                                                    <localNumber>{{localNumber}}</localNumber>
                                            </phoneAddress>
                                    </hasContact>
                            </individual>
                    </Request>
            </Body>
    </Envelope>