QDomNode::childNodes returns and empty QDomNodeList when there ARE child Nodes



  • This has been bugging me and I'm not sure how to debug what the problem is, I would appreciate any ideas.

    I have an XML file that I load into m_pDUTNode. At some point in my code childNodes fails for no apparent reason.

    below is my code with a bunch of extra asserts that I added. only the last one fails

    @ Q_ASSERT(m_pDUTNode->hasChildNodes());

    QDomNode l_deviceNode = m_pDUTNode->firstChildElement("Device");
    if(l_deviceNode.isNull())
    return;

    Q_ASSERT(l_deviceNode.hasChildNodes());

    QDomNode l_FacDefNode = l_deviceNode.firstChildElement(FACTORY_DEFAULT);
    if(l_FacDefNode.isNull())
    return;
    Q_ASSERT(l_FacDefNode.hasChildNodes());

    QDomNode l_TmpTest = l_FacDefNode.firstChild();
    Q_ASSERT(!l_TmpTest.isNull()); // <---this never asserts so l_FacDefNode does have at least one child
    QDomNodeList l_ParamsNodeLst = l_FacDefNode.childNodes();
    Q_ASSERT(l_ParamsNodeLst.count()>0); // <------ This assert fails where did the children go???
    @

    What makes this hard to debug is that the below only fails SOMETIMES usually right after a build. but if I run it again with NO changes to the code, not even rebuilding. it works fine.

    any ideas why childNodes would think that there are no children when clearly there are because firstChild found one?



  • It's a long shot but you could try it without m_pDUTNode being a pointer. QDomNode objects use some kind of explicit sharing mechanism and perhaps it doesn't quite work right with pointers. There's really no need for it to be a pointer anyway.



  • Can you provide a small compilable example that reproduces your problem?



  • Lukas Geyer:: since it doesn't always happen, no. it's an intermittent problem which sometimes happens on the first run after a build.

    joeuser:: I can see what I can do. but it's not that simple. the xml file describes several tests simplified like this:
    @
    <DeviseList>
    <MfgDevice> <!--m_pDUTNode points here-->
    <SKU value="123" description="White enclosure"/><!-- Value listed in combo box-->
    <SKU value="124" description="Black enclosure"/><!-- Value listed in combo box-->
    <SKU value="125" description="Custom enclosure"/><!-- Value listed in combo box-->
    <Device> <!--l_deviceNode -->
    <FACTORY_DEFAULT> <!-- l_FacDefNode -->
    <eeprom_setting address=0x00 value ="0x01/> <!--l_TmpTest & l_ParamsNodeLst -->
    <eeprom_setting address=0x01 value ="0x01/>
    <eeprom_setting address=0x02 value ="0x01/>
    </FACTORY_DEFAULT>
    <other stuff>
    ...
    </other stuff>
    </Device>
    </MfgDevice>

    <MfgDevice> <!--m_pDUTNode points here-->
    <SKU value="223" description="White enclosure"/> <!-- Value listed in combo box-->
    <SKU value="224" description="Black enclosure"/> <!-- Value listed in combo box-->
    <SKU value="225" description="Custom enclosure"/><!-- Value listed in combo box-->
    <Device> <!--l_deviceNode -->
    <FACTORY_DEFAULT> <!-- l_FacDefNode -->
    <eeprom_setting address=0x00 value ="0x02/> <!--l_TmpTest & l_ParamsNodeLst -->
    <eeprom_setting address=0x01 value ="0x02/>
    <eeprom_setting address=0x02 value ="0x02/>
    </FACTORY_DEFAULT>
    <other stuff>
    ...
    </other stuff>
    </Device>
    </MfgDevice>
    </DeviseList>
    @

    a combo box lists all the SKU's and descriptions. when one item is selected, the SKU is used to look up the sku's parent node pointer from a QMap and address gets coped to m_pDUTNode. which is then used later to get the devices' settings.

    I am currently doing this to get the pointer that is used:

    @

      QMap<QString, QDomNode*> m_strMap;
    

    // fill Qmap with sku's and the parent node
    QDomNode *pNodeCopy = new QDomNode(node.cloneNode());

    m_strMap.insert(l_strSKU, pNodeCopy);

    // operator selects SKU from list

    // initialize m_pDUT_Node with sku's parent node
    m_pDUT_Node = m_strMap.value(m_strSKU, NULL);
    Q_ASSERT(m_pDUT_Node != NULL);

    @



  • cloneNode() does not make a deep copy by default. You're operating on DOM fragments, not the real and complete DOM document. No wonder that your code fails.

    If searching the complete document at runtime, I would suggest to read its contents into a decent data structure, instead of working on XML fragments. That's much more reliably.



  • @volker

    huh??? http://developer.qt.nokia.com/doc/qt-4.8/qdomnode.html#cloneNode
    looks like it's a deep copy by default in the documentation. am I reading it wrong?

    I do not search the complete document. each object only know what to do with it's node. for example the device object "knows" that the factory default node is handled by the factory default class. so it passes that child node to an the factory default object. that object know what to do with all the immediate children of that node.

    I am leaning more toward a bug in the debugger where the exe is not upto date when I start a debug execution. I'm starting to see that I only get the problem when it does a build/debug execute in the same step. I need to run more tests to validate that theory though.



  • Sorry, I misread the default value. You're right of course.

    I personally would read in the XML in one pass and store the contents in a lightweight internal format, eg. with some classes/structs containing the pieces. These can be passed around more easily, put into lists, hashes etc.

    Regarding debug runs: make sure you completely rebuild your application and to link against a matching set of Qt and system libraries. Especially Windows is known to cause unexpected crashes when mixing debug and release code and libs.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.