PDA

View Full Version : Having trouble with direct child nodes using QtXml



thelackey3326
16th July 2008, 00:46
I've got an XML file that I'm trying to parse using QtXml in v4.3.3. It's being used to describe a hierarchy of related, as well as very similar, objects used in a schematic-like diagram tool. The actual file I need to get working is considered proprietary to our company, so I've made a test version that I can post (see below) that displays the same issue. If you'll notice, with the way this file is laid out, it lends itself nicely to recursive parsing.

What I'm running into is that the QDomNodeList being returned from QDomNode::childNodes() is not a list of the direct child nodes, as the Qt Assistant says it should be, but rather a list of all child nodes. A little further reading revealed the QDomElement::elementsByTagName(QString) function. When I tried this out and passed it "Element" starting at the <Container name="L1Container" autoAdd="true"> line, I expected to see only one child. Instead I got three--which would be all of the Element tags beneath the <Container>. Am I just misunderstanding the phrase "direct child nodes?" Because, I've done similar parsing with other packages and did not see these results.



<?xml version="1.0" encoding="UTF-8"?>
<ElementDef verMajor="1" verMinor="0">
<Elements>
<Container name="L1Container" autoAdd="true">
<Element name="L1Element1" title="L1Element1Title" label="L1Element1Label" drawn="false">
<Properties>
<Property name="Name" type="String" />
</Properties>
<Children>
<Container name="L2Container" autoAdd="true">
<Element name="L2Element1" title="L2Element1Title" label="L2Element1Label" drawn="false">
<Slots>
<Slot name="Slot1" abbreviation="Sl1" />
<Slot name="Slot2" abbreviation="Sl2" />
</Slots>
<Signals>
<Signal name="Signal1" abbreviation="Si1" event="CompleteEvent">
<Argument value="FakeName" />
</Signal>
<Signal name="Signal2" abbreviation="Si2" event="CompleteEvent">
<Argument value="FakeName" />
</Signal>
</Signals>
</Element>
<Element name="L2Element2" title="L2Element2Title" label="L2Element2Label" drawn="false">
<Slots>
<Slot name="Slot1" abbreviation="Sl1" />
<Slot name="Slot2" abbreviation="Sl2" />
</Slots>
<Signals>
<Signal name="Signal1" abbreviation="Si1" event="CompleteEvent">
<Argument value="FakeName" />
</Signal>
<Signal name="Signal2" abbreviation="Si2" event="CompleteEvent">
<Argument value="FakeName" />
</Signal>
</Signals>
</Element>
</Container>
</Children>
</Element>
</Container>
</Elements>
</ElementDef>


Here is (basically) the code I've tried in an effort to get the children I want. You may notice the 'i' preceding my objects. Some use 'i' for integer and some use it for interface. It's what I use to denote a class instance so that I don't have to define (and remember) innumerable Hungarian-like abbreviations for the classes I use. Just a simple 'i' and an appropriate name.



QDomNodeList iChildren;

/* Here I expected to only get L1Element1, but got it and it's children named Element.*/
iChildren = iChild.elementsByTagName("Element"); //iChild is a QDomElement straight from the DOM

/*This just gave me everything below L1Container, which is less than useless.*/
iChildren = iChild.childNodes();


If anyone has a clue what might be going on, I'd love to know. As it is, I need to get this thing moving so I'll have to use a different parsing API.

aamer4yu
16th July 2008, 08:41
From the docs :

QDomNodeList QDomElement::elementsByTagName ( const QString & tagname ) const
Returns a QDomNodeList containing all descendent elements of this element that are called tagname. The order they are in the node list is the order they are encountered in a preorder traversal of the element tree.

so the behaviour of elementsByTagName in ur code is justified.

As for the childNodes(), Are you sure you were on the <Container name="L1Container" autoAdd="true"> tag when you used the childNodes() function ??

Thirdly... what is iChild in your code ? How are you assigning value to it ??

thelackey3326
16th July 2008, 22:12
I see your point about elementsByTagName. Must've glossed over that when I read it earlier. iChild has a comment next to it describing what it is and where it's from, but in fact it was related to a bug I found in my code, so it no longer exists.

The way I was processing the children of both a <Container> and an <Element> was to get their child nodes (actually in the case of the <Element>, it was the children of <Children>) with childNodes() and parse each in a for loop.

What I've now done, thanks to an example from a work acquaintance, is grab the firstChildElement() and use something similar to:


QDomElement iChild = iParent.firstChildElement();
while (!iChild.isNull())
{
parseFunction(iChild);
iChild = iChild.nextSiblingElement();
}

Strangly enough, I had used this method before with TinyXML in a school project a while back but it didn't hit me until I saw it in an example. But, it is now working and I'm on to other things.

Thanks for the reply!