PDA

View Full Version : Need help merging QDomNodes



Spoon
28th March 2011, 19:24
I have three xml files I'd like to merge.

base.xml


<symbols>
<circle>
<n_points>0</n_points>
</circle>
</symbols>


rect.xml


<rectangle>
<points>
<n_points>4</n_points>
<point>
<x>1.0</x>
<y>2.0</y>
</point>
<point>
<x>6.0</x>
<y>2.0</y>
</point>
<point>
<x>1.0</x>
<y>4.0</y>
</point>
<point>
<x>6.0</x>
<y>4.0</y>
</point>
</points>
</rectangle>


3d.xml


<rectangle>
<points>
<point>
<z>7.0</z>
</point>
<point>
<z>8.0</z>
</point>
<point>
<z>9.0</z>
</point>
<point>
<z>10.0</z>
</point>
</points>
</rectangle>


I want the end result to be like this...


<symbols>
<circle>
<n_points>0</n_points>
</circle>
<rectangle>
<points>
<n_points>4</n_points>
<point>
<x>1.0</x>
<y>2.0</y>
<z>7.0</z>
</point>
<point>
<x>6.0</x>
<y>2.0</y>
<z>8.0</z>
</point>
<point>
<x>1.0</x>
<y>4.0</y>
<z>9.0</z>
</point>
<point>
<x>6.0</x>
<y>4.0</y>
<z>10.0</z>
</point>
</points>
</rectangle>
</symbols>


I constructed the following method:


void DomHelper::merge(QDomNode mergeInto, const QDomNode &mergeFrom) {
bool foundMatchingNode = false;
QDomNodeList children = mergeInto.childNodes();

for (int i = 0; i < children.size(); ++i) {
if (children.at(i) == mergeFrom) {
foundMatchingNode = true;
break;
}
}

if (foundMatchingNode) {
DomElementContainer elements(mergeInto, mergeFrom.toElement().tagName());
foreach(QDomElement element, elements) {
QDomNodeList elementChildren = mergeFrom.childNodes();
int count = elementChildren.size();
for (int i = 0; i < count; ++i) {
merge(element, elementChildren.at(i));
}
}
} else {
mergeInto.appendChild(mergeFrom);
m_doc = mergeInto.ownerDocument;
}


DomElementContainer is just a class I made instead of using elementsByTagName() ... actually I borrowed it from someone else and modified it but still, it works.

m_doc is what I return to my QTreeView widget to view the result. The result is not what I want though and I've been staring at my code for too long so I can't figure out how to fix it either. I would greatly appreciate some help here.

One other issue is that the merge should be correctly done no matter the order although base.xml always exists before the others. So...

base << rect << 3d

shall produce the same output as....

base << 3d << rect

wysota
28th March 2011, 22:05
DomElementContainer is just a class I made instead of using elementsByTagName() ... actually I borrowed it from someone else and modified it but still, it works.
Not from someone else but from me :)


The result is not what I want
So what's wrong with it?

Spoon
29th March 2011, 02:02
So what's wrong with it?

When I merge base >> rect >> 3d everything works out just fine but when I do base >> 3d >> rect, I end up with something that looks like this.



<symbols>
<circle>
<n_points>0</n_points>
</circle>
<rectangle>
<points>
<point>
<z>7.0</z>
<x>6.0</x> <!-- should be 1.0 -->
<y>4.0</y> <!-- should be 2.0 -->
</point>
<point>
<z>8.0</z>
<x>2.0</x> <!-- should be 6.0 -->
<y>1.0</y> <!-- should be 2.0 -->
</point>
<point>
<z>9.0</z>
<x>6.0</x> <!-- should be 1.0 --> <!-- y missing completely -->
</point>
<point>
<z>10.0</z>
<y>4.0</y> <!-- can't tell if this is correct or not but x is missing -->
</point>
</points>
<n_points>4</n_points>
</rectangle>
</symbols>


The order of the tags within the parent node is not relevant but yeah, I screwed up my recursive calls, sadly I still can't see how can fix it.
Oh and I made a little typo.


if (children.at(i) == mergeFrom) {

should have been ...


if (compare(children.at(i), mergeFrom)) {


where compare is a small routine comparing nodeName() and nodeType() of the two arguments, returning true if both are equal.

Good job on that element container class btw. I like it :D

wysota
29th March 2011, 03:41
It would be easiest for you if you used attributes (like id) for each point to uniquely identify them. Otherwise it is not possible to be sure that you process the right nodes. Someone could remove data from one set but not from the other and everything would go out of sync. Of course it is possible to operate on the order of items (first child, second child, etc.) but I would really advise against it.