Return all nodes from XML file, even when they are empty

11,884

what i'm after is a list of Userbeans, which are in themselves a list

You need to think in terms of "nodes", not "lists." selectNodes returns a pointer to a set of nodes, but when you iterate through it you wind up with an IXMLDOMNode, not a Node List. You can only get a nodeList by calling a method, such as selectNodes.

You can to call selectNodes again, or just use the IXMLDOMNode's childNodes property, Documented at MSDN

Dim userBeanList As MSXML2.IXMLDOMNodeList
Dim userbean As MSXML2.IXMLDOMNode
Dim beanChild As MSXML2.IXMLDOMNode

Set userBeanList = xmlDoc.selectNodes("//UserBean")
For Each userBean In userBeanList 
    For Each beanChild In userBean.childNodes
          Debug.Print beanChild.nodeName & ":" & beanChildText
    Next beanChild
Next userBean

Note that with a proper XPath Query, you can just select a list of nodes that meet your criteria. And since this is VBA, you can skip the explicit declarations unless you're going to take advantage of the intellisense.

dim badNodes, badNode
set badNodes = xmlDoc.selectNodes("//UserBean/*[not(text())]")
if badNodes.length < 1 then
  debug.Print "All good!"
else
  debug.Print "following nodes are empty:"
  For Each badNode in badNodes
    debug.print " - " & badNode.name
  next badNode
endif
Share:
11,884
zoonosis
Author by

zoonosis

Hobbyist mobile app developer

Updated on June 06, 2022

Comments

  • zoonosis
    zoonosis almost 2 years

    I have an XML file retrieved via WSDL in Access 2010 via VBA. The XML file is sitting in this variable

    Dim xmlDoc As New DOMDocument60
    

    The part of the XML I'm interested in looks like the below and basically just reiterates itself for every UserBean. A UserBean is basically a user account in a system.

    <UserBean xsi:type="ns1:UserBean">  
        <primaryKey xsi:type="xsd:string">49084</primaryKey>  
        <updateIndex xsi:type="xsd:int">14</updateIndex>  
        <deleted xsi:type="xsd:boolean">false</deleted>  
        <loginID xsi:type="xsd:string">61420313556</loginID>  
        <name xsi:type="xsd:string">Andrew Mills</name>    
        <teams xsi:type="soapenc:Array" soapenc:arrayType="xsd:string[1]">  
            <string xsi:type="xsd:string">Maintenance</string>  
        </teams>  
        <timezone xsi:type="xsd:string">Australia/Brisbane</timezone>  
        <userTypePK xsi:type="xsd:string">3776</userTypePK>  
        <description xsi:type="xsd:string"/>  
        <emailAddress xsi:type="xsd:string"/>  
        <phoneNumber xsi:type="xsd:string"/>  
        <faxNumber xsi:type="xsd:string"/>  
        <pagerNumber xsi:type="xsd:string"/>  
        <mobileNumber xsi:type="xsd:string">61420313556</mobileNumber>  
        <securityQuestion xsi:type="xsd:string">__INVALID</securityQuestion>  
        <securityAnswer xsi:type="xsd:string"/>  
        <synchronisation xsi:type="soapenc:Array" soapenc:arrayType="ns2:SynchronisationBean[0]" xmlns:ns2="http://soap2.nads.econz.co.nz"/>  
    </UserBean>
    

    The problem is that not every field is mandatory to be filled in.
    Therefore some nodes have no data
    Using the MSXML2 library in VBA only returns nodes if there is actually text in it. Therefore the code below will return a variable amount of nodes depending on what each userbean contains. For example some users dont have a mobileNumber populated.

    Set nodes xmlDoc.selectNodes("//UserBean")
    For Each node in nodes  
        debug.print node.text  
    next node
    

    The above code returns a long string that has all of the values of all of the child nodes in it (with respect to the Userbean node), but only the ones that have text. I'm trying to get this into a table in Access and if some of the nodes are missing some of the time, I've got no way of tracking it... or do I?

    How do I return ALL nodes whether they are populated or not
    OR
    How do I identify the name of the node that has the text so I know where to put the value into the table in Access?

    UPDATE
    Further to the below comments, what i'm after is a list of Userbeans, which are in themselves a list...so in fact i'm after a list of lists...so with that in mind I tried the below but it failed at the first For Each loop. Obviously that type of loop can't handle using lists as a counter for another list. Is there a way around this?

    Dim node As MSXML2.IXMLDOMNode
    Dim userbeans As MSXML2.IXMLDOMNodeList
    Dim userbean As MSXML2.IXMLDOMNodeList
    
    Set userbeans = xmlDoc.selectNodes("//UserBean")
    For Each userbean In userbeans '**Type mismatch error here**
        For Each node In userbean
              Debug.Print node.nodeName & ":" & node.Text
        Next node
    Next userbean