How to iterate a boost property tree?
Asked Answered
E

5

28

I am know approaching to boost property tree and saw that it is a good feature of boost libs for c++ programming.

Well, I have one doubt? how to iterate a property tree using iterators or similar?

In reference there is just an example of browsing the tree through:

BOOST_FOREACH

But is there nothing more? Something like an stl-like container? It would be a better solution, speaking about code quality....

Epistle answered 3/1, 2011 at 17:37 Comment(0)
T
18

BOOST_FOREACH is just a convenient way for iterating that can be done by iterator, begin() and end()

Your_tree_type::const_iterator end = tree.end();
for (your_tree_type::const_iterator it = tree.begin(); it != end; ++it)
    ...

And since C++11 it's:

for (auto& it: tree)
    ...
Thacher answered 3/1, 2011 at 17:45 Comment(4)
I'll test in the afternoon... ah, didn't think it was so easy... I'll let you know soon :)Epistle
the top level of ptree, to iterate all leaves you need to do this recursivelyThacher
The notation for the C++11 example could be improved: it is now a child of ptree, not an iterator as in the first example.Kaisership
The interesting part in the second example is the ... or the auto. See below for details.Ammo
K
33

Here is what I came up with after much experimentation. I wanted to share it in the community because I couldn't find what I wanted. Everybody seemed to just post the answer from the boost docs, which I found to be insufficient. Anyhow:

#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <string>
#include <iostream>

using namespace std; 
using boost::property_tree::ptree; 

string indent(int level) {
  string s; 
  for (int i=0; i<level; i++) s += "  ";
  return s; 
} 

void printTree (ptree &pt, int level) {
  if (pt.empty()) {
    cerr << "\""<< pt.data()<< "\"";
  }

  else {
    if (level) cerr << endl; 

    cerr << indent(level) << "{" << endl;     

    for (ptree::iterator pos = pt.begin(); pos != pt.end();) {
      cerr << indent(level+1) << "\"" << pos->first << "\": "; 

      printTree(pos->second, level + 1); 
      ++pos; 
      if (pos != pt.end()) {
        cerr << ","; 
      }
      cerr << endl;
    } 

   cerr << indent(level) << " }";     
  }

  return; 
}

int main(int, char*[]) {

  // first, make a json file:
  string tagfile = "testing2.pt"; 
  ptree pt1;
  pt1.put("object1.type","ASCII");  
  pt1.put("object2.type","INT64");  
  pt1.put("object3.type","DOUBLE");  
  pt1.put("object1.value","one");  
  pt1.put("object2.value","2");  
  pt1.put("object3.value","3.0");  
  write_json(tagfile, pt1); 

  ptree pt;
  bool success = true; 

  try {
      read_json(tagfile, pt); 
      printTree(pt, 0); 
      cerr << endl; 
  }catch(const json_parser_error &jpe){
      //do error handling
      success = false
  }

  return success; 
}

Here is the output:

rcook@rzbeast (blockbuster): a.out
{
  "object1": 
  {
    "type": "ASCII",
    "value": "one"
   },
  "object2": 
  {
    "type": "INT64",
    "value": "2"
   },
  "object3": 
  {
    "type": "DOUBLE",
    "value": "3.0"
   }
 }
rcook@rzbeast (blockbuster): cat testing2.pt 
{
    "object1":
    {
        "type": "ASCII",
        "value": "one"
    },
    "object2":
    {
        "type": "INT64",
        "value": "2"
    },
    "object3":
    {
        "type": "DOUBLE",
        "value": "3.0"
    }
}
Karen answered 20/6, 2013 at 17:12 Comment(0)
T
18

BOOST_FOREACH is just a convenient way for iterating that can be done by iterator, begin() and end()

Your_tree_type::const_iterator end = tree.end();
for (your_tree_type::const_iterator it = tree.begin(); it != end; ++it)
    ...

And since C++11 it's:

for (auto& it: tree)
    ...
Thacher answered 3/1, 2011 at 17:45 Comment(4)
I'll test in the afternoon... ah, didn't think it was so easy... I'll let you know soon :)Epistle
the top level of ptree, to iterate all leaves you need to do this recursivelyThacher
The notation for the C++11 example could be improved: it is now a child of ptree, not an iterator as in the first example.Kaisership
The interesting part in the second example is the ... or the auto. See below for details.Ammo
B
11

I ran into this issue recently and found the answers incomplete for my need, so I came up with this short and sweet snippet:

using boost::property_tree::ptree;

void parse_tree(const ptree& pt, std::string key)
{
  std::string nkey;

  if (!key.empty())
  {
    // The full-key/value pair for this node is
    // key / pt.data()
    // So do with it what you need
    nkey = key + ".";  // More work is involved if you use a different path separator
  }

  ptree::const_iterator end = pt.end();
  for (ptree::const_iterator it = pt.begin(); it != end; ++it)
  {
    parse_tree(it->second, nkey + it->first);
  }
}

Important to note is that any node, except the root node can contain data as well as child nodes. The if (!key.empty()) bit will get the data for all but the root node, we can also start building the path for the looping of the node's children if any.

You'd start the parsing by calling parse_tree(root_node, "") and of course you need to do something inside this function to make it worth doing.

If you are doing some parsing where you don't need the FULL path, simply remove the nkey variable and it's operations, and just pass it->first to the recursive function.

Bullard answered 1/9, 2014 at 20:30 Comment(0)
P
3

An addition to the answer How to iterate a boost property tree? :

In the C++11 style range based for for (auto node : tree), each node is a std::pair<key_type, property_tree>

Whereas in the manually written iteration

Your_tree_type::const_iterator end = tree.end();
for (your_tree_type::const_iterator it = tree.begin(); it != end; ++it)
...

the iterator it is a pointer to such a pair. It's a tiny difference in usage. For example, to access the key, one would write it->first but node.first.

Posted as a new answer, because my proposed edit to the original answer was rejected with the suggestion to post a new answer.

Preposition answered 7/3, 2019 at 0:25 Comment(0)
T
-1

BFS based print ptree traversal, May be used if we want to do some algorithmic manipulation

int print_ptree_bfs(ptree &tree) {
try {
    std::queue<ptree*> treeQ;
    std::queue<string> strQ;

    ptree* temp;

    if (tree.empty())
        cout << "\"" << tree.data() << "\"";

    treeQ.push(&tree);
    //cout << tree.data();
    strQ.push(tree.data());

    while (!treeQ.empty()) {
        temp = treeQ.front();
        treeQ.pop();

        if (temp == NULL) {
            cout << "Some thing is wrong" << std::endl;
            break;
        }
        cout << "----- " << strQ.front() << "----- " << std::endl;
        strQ.pop();

        for (auto itr = temp->begin(); itr != temp->end(); itr++) {
            if (!itr->second.empty()) {
                //cout << itr->first << std::endl;
                treeQ.push(&itr->second);
                strQ.push(itr->first);
            } else {
                cout<<itr->first << " " << itr->second.data() << std::endl;
            }
        }

        cout << std::endl;

     }
   } catch (std::exception const& ex) {
    cout << ex.what() << std::endl;
   }
   return EXIT_SUCCESS;
  }
Tellus answered 7/8, 2018 at 18:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.