简体   繁体   English

如何迭代提升属性树?

[英]How to iterate a boost property tree?

I am know approaching to boost property tree and saw that it is a good feature of boost libs for c++ programming.我知道接近 boost 属性树,并看到它是用于 C++ 编程的 boost 库的一个很好的特性。

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?像stl一样的容器? It would be a better solution, speaking about code quality....这将是一个更好的解决方案,谈到代码质量......

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.每个人似乎都只是从 boost 文档中发布了答案,我发现这是不够的。 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"
    }
}

BOOST_FOREACH is just a convenient way for iterating that can be done by iterator, begin() and end() BOOST_FOREACH 只是一种方便的迭代方式,可以由迭代器、begin() 和 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:从 C++11 开始,它是:

for (auto& it: tree)
    ...

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. if (!key.empty())位将获取除根节点之外的所有数据,我们也可以开始构建节点子节点的循环路径(如果有)。

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.您可以通过调用parse_tree(root_node, "")开始解析,当然您需要在此函数中做一些事情以使其值得做。

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.如果您在不需要完整路径的情况下进行一些解析,只需删除nkey变量及其操作,然后将it->first传递给递归函数。

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>在基于 for for (auto node : tree)的 C++11 样式范围中,每个node都是一个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是一个指向这样一对的指针。 It's a tiny difference in usage.用法上的差别很小。 For example, to access the key, one would write it->first but node.first .例如,要访问密钥,可以写node.first it->firstnode.first

Posted as a new answer, because my proposed edit to the original answer was rejected with the suggestion to post a new answer.发布为新答案,因为我建议对原始答案进行编辑被拒绝,并建议发布新答案。

BFS based print ptree traversal, May be used if we want to do some algorithmic manipulation基于 BFS 的打印 ptree 遍历,如果我们想做一些算法操作,可以使用

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM