Как перебрать дерево свойств буста? - PullRequest
18 голосов
/ 03 января 2011

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

Ну, у меня есть одно сомнение? Как перебрать дерево свойств, используя итераторы или аналогичные?

В качестве примера приведем пример просмотра дерева:

BOOST_FOREACH

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

Ответы [ 5 ]

25 голосов
/ 20 июня 2013

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

#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"
    }
}
17 голосов
/ 03 января 2011

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

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

А в C ++ 11 это:

for (auto it: tree)
    ...
7 голосов
/ 02 сентября 2014

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

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 рекурсивной функции.

0 голосов
/ 07 марта 2019

Дополнение к ответу Как выполнить итерацию дерева свойств повышения? :

В диапазоне стилей C ++ 11, основанном на for (auto node : tree), каждый node является std::pair<key_type, property_tree>

В то время как в написанной вручную итерации

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

итератор it является указателем на такую ​​пару.Это крошечная разница в использовании.Например, чтобы получить доступ к ключу, нужно написать it->first, но node.first.

Опубликовано как новый ответ, потому что мое предложенное редактирование исходного ответа было отклонено с предложением опубликовать новый ответ.

0 голосов
/ 07 августа 2018

Обход печати на основе 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;
  }
...