Как перебрать дерево свойств boost?

Я знаю, что приближаюсь к дереву свойств повышения и увидел, что это хорошая функция библиотек повышения для программирования на С++.

Ну у меня одно сомнение? как перебрать дерево свойств с помощью итераторов или подобных?

В ссылке есть только пример просмотра дерева:

BOOST_FOREACH

Но больше ничего нет? Что-то вроде stl-контейнера? Это было бы лучшим решением, говоря о качестве кода....


person Andry    schedule 03.01.2011    source источник


Ответы (5)


BOOST_FOREACH — это просто удобный способ итерации, которую можно выполнить с помощью итератора, begin() и end().

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

А так как С++ 11 это:

for (auto& it: tree)
    ...
person Andriy Tylychko    schedule 03.01.2011
comment
Днём проверю... ах, не думал, что это так просто... Скоро сообщу :) - person Andry; 04.01.2011
comment
верхний уровень ptree, чтобы перебрать все листья, вам нужно сделать это рекурсивно - person Andriy Tylychko; 04.01.2011
comment
Нотация для примера C++11 может быть улучшена: it теперь является потомком ptree, а не итератором, как в первом примере. - person P-Gn; 05.03.2015
comment
Интересная часть во втором примере — это ... или auto. Подробнее см. ниже. - person Andreas Haferburg; 21.07.2020

Вот что у меня получилось после долгих экспериментов. Я хотел поделиться этим в сообществе, потому что я не мог найти то, что хотел. Казалось, что все просто опубликовали ответ из документации по ускорению, которого мне показалось недостаточным. Во всяком случае:

#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; 
}

Вот результат:

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"
    }
}
person Rich    schedule 20.06.2013

Недавно я столкнулся с этой проблемой и нашел ответы неполными для своих нужд, поэтому я придумал этот короткий и приятный фрагмент:

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);
  }
}

Важно отметить, что любой узел, кроме корневого узла, может содержать данные, а также дочерние узлы. Бит if (!key.empty()) получит данные для всех, кроме корневого узла, мы также можем начать строить путь для зацикливания дочерних узлов, если они есть.

Вы бы начали синтаксический анализ, вызвав parse_tree(root_node, ""), и, конечно, вам нужно что-то сделать внутри этой функции, чтобы это стоило делать.

Если вы выполняете синтаксический анализ, где вам не нужен ПОЛНЫЙ путь, просто удалите переменную nkey и ее операции и просто передайте it->first рекурсивной функции.

person random_acts    schedule 01.09.2014


Обход ptree печати на основе BFS. Может использоваться, если мы хотим выполнить некоторые алгоритмические манипуляции.

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;
  }
person Pankaj    schedule 07.08.2018