Reputation: 14615
I have just discovered boost::property_tree, which seems the perfect answer to my problem. I wrote a small test program to extract specific data from an xml file. I have used the example provided in the documentation as a guide. The xml file: test.xml:
<section>
<GROUP>
<g_name>ABC</g_name>
<fields>
<row>
<name>A</name>
<datatype>string</datatype>
<field_size>6</field_size>
<value>ABC</value>
</row>
<row>
<name>B</name>
<datatype>integer</datatype>
<field_size>5</field_size>
<value>00107</value>
</row>
<row>
<name>C</name>
<datatype>string</datatype>
<field_size>20</field_size>
<value>LOTS OF LETTERS </value>
</row>
</fields>
</GROUP>
<GROUP>
<g_name>CDE</g_name>
<fields>
<row>
<name>A</name>
<datatype>string</datatype>
<field_size>6</field_size>
<value>CDE</value>
</row>
<row>
<name>B</name>
<datatype>integer</datatype>
<field_size>5</field_size>
<value>00100</value>
</row>
<row>
<name>F</name>
<datatype>integer</datatype>
<field_size>4</field_size>
<value>1970</value>
</row>
</fields>
</GROUP>
</section>
The code:
using boost::property_tree::ptree;
struct t_collection
{
ptree pt;
void load(const std::string &filename);
void print();
};
void t_collection::load(const std::string &filename)
{
read_xml(filename, pt);
}
void t_collection::print()
{
BOOST_FOREACH(ptree::value_type &v, pt.get_child("section.GROUP"))
BOOST_FOREACH(ptree::value_type &v, pt.get_child("section.GROUP"))
{
printf("X: %s->", v.second.data().c_str());
//prints X: ABC ->
BOOST_FOREACH(ptree::value_type &w, pt.get_child("section.GROUP.fields.row"))
printf("%s\n", w.second.data().c_str());
//prints A, string, 6, ABC - that is good for first iteration but there should be 3 iterations here
}
//then prints X: and just "" and repeats the set from the first one
}
int main()
{
try
{
t_collection t1;
t1.load("test.xml");
t1.print();
}
catch (std::exception &e)
{
std::cout << "Error: " << e.what() << "\n";
}
return 0;
}
Note: I am trying to extract the values (ABC and the inner values, like A - string - 6 - ABC, for each GROUP - and each set of "row", which I will process and then output in a different format). Please see comment in code for something I tried.
So far the best result was with: (contents inside print():
BOOST_FOREACH(ptree::value_type &z, pt.get_child("section"))
//BOOST_FOREACH(ptree::value_type &v, pt.get_child("section.GROUP"))
{
printf("X: %s->", pt.get<std::string>("section.GROUP.g_mame", "default").c_str());
//prints X: ABC ->
BOOST_FOREACH(ptree::value_type &w, pt.get_child("section.GROUP.fields.row"))
{
printf("%s\n", pt.get<std::string>("section.GROUP.fields.row.name", "name").c_str());
printf("%s\n", pt.get<std::string>("section.GROUP.fields.row.datatype", "type").c_str());
printf("%s\n", pt.get<std::string>("section.GROUP.fields.row.field_size", "size").c_str());
printf("%s\n", pt.get<std::string>("section.GROUP.fields.row.value", "value").c_str());
}
}
//prints x: default->A, string, 6, ABC (3 times) then repeat identically
I can't get the data from more than one record ! Please help, give me a suggestion - what am I doing wrong ?
Thank you.
Upvotes: 0
Views: 2044
Reputation: 18349
You are missing a level in your iteration. You need to iterate over the elements that have multiple children with the same name.
std::pair<ptree::const_assoc_iterator, ptree::const_assoc_iterator>
r(pt.get_child("section").equal_range("GROUP"));
for (ptree::const_assoc_iterator i(r.first); i != r.second; ++i) {
// Do something with each group.
}
Repeat as appropriate as you descend the tree.
Upvotes: 2