rapidxml: how to iterate through nodes? Leaves out last sibling
Asked Answered
C

3

9

Using rapidxml I'm wanting to loop through a set of nodes, and am using what I found to be the best way to do this (from trusty stackoverflow, the doc doesn't appear to have an example of iteration):

while (curNode->next_sibling() !=NULL ) {
    string shiftLength = curNode->first_attribute("shiftLength")->value();
    cout << "Shift Length " << "\t" << shiftLength << endl;
    curNode = curNode->next_sibling();        
}

Unfortunately, on my OSX 10.6 this is leaving out the last sibling node - I guess because in the last iteration of the loop, next_sibling is called twice. I can get at this last node if I write, after the loop:

cout << " LAST IS: " << curNode->first_attribute("shiftLength")->value();

...but that's dodgy, and the program quits at that point.

First question: Could this be a unique foible of my setup (OSX 10.6) or have I coded wrong?

Second question: Does anyone have an example of what they believe is the correct way to iterate through an unknown number of XML nodes using rapidxml?

Thanks guys

Pete

Cuttle answered 5/3, 2011 at 10:52 Comment(1)
Think of loops in terms of invariants. Yours executes for all nodes with non-NULL next siblings. This is not true for the last node.Peralta
W
12

This is the proper way to iterate though all child nodes of a node in rapidxml:

xml_node<> *node = ...
for (xml_node<> *child = node->first_node(); child; child = child->next_sibling())
{
    // do stuff with child
}
Woolfolk answered 16/7, 2011 at 0:32 Comment(3)
This is not convenient if you're about to pick one random node (eg. you need to know number of nodes and pick one at offset X)Charis
@Tomas There is always a tradeoff in data structures. To allow fast addition during parsing, rapidxml uses linked lists for child nodes and attributes. Therefore, direct indexing by number is not possible. But you have to remember that rapidxml is not about convenience but performance.Woolfolk
I've written a function that gives you (at a cost of performance hit) std::vector full of child nodes. As soon as the document tree is altered the list is invalid.Charis
C
6

Here's the final code in working form:

xml_node<> *curNode = ... // e. g. parentNode->first_node();
while (curNode) {
    string start = curNode->first_attribute("start")->value();
    string numStaff = curNode->first_attribute("numStaff")->value();
    cout << start << "\t" << numStaff << endl;
    curNode = curNode->next_sibling();
}
Cuttle answered 5/3, 2011 at 11:26 Comment(0)
C
2
while (curNode->next_sibling() !=NULL )

This says "while there's one more node left after the one I'm working on". That's why your loop's stopping early - when curNode is the final sibling, its "next_sibling" will be NULL. This test should work better:

while (curNode !=NULL )
Castile answered 5/3, 2011 at 11:7 Comment(1)
Thanks Neil (I tried that approach before but get a BAD ACCESS in rapidxml.hpp (line 1031 v 1.13) - aaaaggghh my mistake though I'd tried to look up an attribute after the loop had finished). Thanks again.Cuttle

© 2022 - 2024 — McMap. All rights reserved.