C++ 如何迭代提升属性树?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4586768/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 15:50:47  来源:igfitidea点击:

How to iterate a boost property tree?

c++xmliteratorboost-propertytree

提问by Andry

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? It would be a better solution, speaking about code quality....

但没有更多了吗?像stl一样的容器?这将是一个更好的解决方案,谈到代码质量......

采纳答案by Andriy Tylychko

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 in C++11 it's:

在 C++11 中,它是:

for (auto it: tree)
    ...

回答by Rich

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:

这是我经过多次实验得出的结论。我想在社区中分享它,因为我找不到我想要的东西。每个人似乎都只是从 boost 文档中发布了答案,我发现这是不够的。无论如何:

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

回答by random_acts

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 nkeyvariable and it's operations, and just pass it->firstto the recursive function.

如果您在不需要完整路径的地方进行一些解析,只需删除nkey变量及其操作,然后传递it->first给递归函数即可。

回答by user766308

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 nodeis a std::pair<key_type, property_tree>

在基于 for 的 C++11 样式范围中for (auto node : tree),每个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 itis a pointer to such a pair. It's a tiny difference in usage. For example, to access the key, one would write it->firstbut node.first.

迭代器it是指向这样一对的指针。用法上的差别很小。例如,要访问密钥,可以写it->first但是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.

发布为新答案,因为我建议对原始答案进行编辑被拒绝,并建议发布新答案。

回答by Pankaj

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