为自定义路径类型设置 boost property_tree

Posted

技术标签:

【中文标题】为自定义路径类型设置 boost property_tree【英文标题】:Setting up boost property_tree for a custom path type 【发布时间】:2017-07-25 09:30:42 【问题描述】:

我需要在我的程序中使用 boost::property_tree。现在我很难弄清楚如何将它与自定义路径类型一起使用。我想要的路径类型是Framework::CommonClientServer::InterfacePathChain_t

它是这样定义的:

typedef std::vector<InterfaceID_t> InterfacePathChain_t;
typedef int InterfaceID_t;

所以基本上路径类型应该是std::vector&lt;int&gt;

例如:

     0
    / \
   1   2
  /   / \
 3   4   5

这些节点将具有以下路径:

0: 0
1: 0, 0
2: 0, 1
3: 0, 0, 0
4: 0, 1, 0
5: 0, 1, 1

我已经通过以下方式定义了path_of 结构:

namespace boost  namespace property_tree 
template<> class path_of<Framework::CommonClientServer::InterfacePathChain_t>

public:

    typedef Framework::CommonClientServer::InterfacePathChain_t key_type;

    struct type 
    
        key_type path;  
    public:
        type(key_type pathVal)
        
            path = pathVal;
        

        std::string dump() const    
        
            std::ostringstream oss;
            if (path.size() > 0)
            
                key_type::const_iterator it = path.begin();
                oss << *it;
                ++it;
                while(it != path.end())
                
                    oss << '.' << *it;
                    ++it;
                ;
            
            return oss.str();
        

        bool empty() const  
        
            return path.size() == 0;
        

        key_type reduce()   
        
            key_type res;
            res.push_back(*path.begin());
            path.erase(path.begin());
            return res;
        

        bool single() const 
        
            return path.size() == 1;
        
    ;
;

之后,我尝试将 2 个具有不同路径和 ID 的节点添加到树中,但它似乎不起作用。实际上,第一个节点是用我设置的 id 添加的(路径是 0)。但是似乎没有添加第二个节点(路径是 0, 0 所以它应该是节点 1 的子节点)。当我尝试遍历树时,会发生这种情况:

MetaStorageTree tree;
Framework::CommonClientServer::InterfacePathChain_t path;
path.push_back(0);
MetaStorageTreeNode* node = new MetaStorageTreeNode(1);
tree.put(path, node);
Framework::CommonClientServer::InterfacePathChain_t path1;
path1.push_back(0);
path1.push_back(0);
MetaStorageTreeNode* node1 = new MetaStorageTreeNode(2);
tree.put(path1, node);
for (auto it : tree)
    
        for (int i = 0; i < it.first.size(); i++)
        
            std::cout << it.first[i];
        
        std::cout << std::endl;
        if (it.second.empty()) //this returns true so node1 does not have a child
        
            std::cout << "empty" << std::endl;
        
    

我相信我对我需要的 boost::property_tree 中的所有内容进行类型定义有问题,但找不到关于该主题的任何足够信息,因为 property_tree 的大多数使用都专用于 JSON 解析,因此标准 std: :string 路径类型被使用。

【问题讨论】:

“property_tree 的大部分都专用于 JSON 解析”是无意义的。事实上,它的 JSON 支持很糟糕,而且它还有两个序列化后端。 【参考方案1】:

我认为逻辑上的误解是其根源。您实际上并没有专门化一棵树来使用另一种路径类型。

您将它专门用于另一个 key_type(在这种情况下,您希望它是 InterfaceID_t)。查询中使用的路径类型只是隐式派生的,从不存储。

因此路径类型不能“是”InterfacePathChain_t,因为它必须是path_of&lt;key_type&gt;::type,并且必须遵守您在上面实现的概念。不过,您可以path_type 隐式转换为InterfacePathChain_t

实施所有必需的更改,我们得出以下测试程序:

using MetaStorageTree = boost::property_tree::basic_ptree<Framework::CommonClientServer::InterfaceID_t, std::string>;

void dump_tree_for_debug(MetaStorageTree const&);

int main() 
    MetaStorageTree tree;

    using Framework::CommonClientServer::InterfacePathChain_t;
    tree.put(InterfacePathChain_t0, "0");
    tree.put(InterfacePathChain_t0, 0, "1");
    tree.put(InterfacePathChain_t0, 1, "2");
    tree.put(InterfacePathChain_t0, 0, 0, "3");
    tree.put(InterfacePathChain_t0, 1, 0, "4");
    tree.put(InterfacePathChain_t0, 1, 1, "5");

    dump_tree_for_debug(tree);

我选择使用deque&lt;int&gt; 来实现path_of&lt;int&gt;::type,这对任务来说更自然,并强调它确实需要与@987654332 相同@。

我将输出添加到 XML;但是,PropertyTree 的序列化后端假设 path_type::value_type 是有效的流字符类型。由于您选择的树专业化不是这种情况,因此我已将一个辅助函数添加到 convert_weird_tree 到标准 ptree

Live On Coliru

#include <boost/property_tree/ptree.hpp>
#include <deque>
#include <vector>

namespace Framework  namespace CommonClientServer 
    using InterfaceID_t = int;
    using InterfacePathChain_t = std::vector<InterfaceID_t>;
 

namespace boost  namespace property_tree 
    template<> struct path_of<Framework::CommonClientServer::InterfaceID_t>
    
        typedef Framework::CommonClientServer::InterfaceID_t key_type;
        typedef std::deque<key_type> path_type;

        struct type 
        
            path_type path;  
        public:
            // this allows us to easily convert paths to string in convert_weird_tree... (DEBUG)
            explicit type(Framework::CommonClientServer::InterfaceID_t id) : path  id  

            type(Framework::CommonClientServer::InterfacePathChain_t chain) : path(chain.begin(), chain.end()) 
            type(path_type pathVal) : path(std::move(pathVal)) 

            std::string dump() const    
                std::string r;
                for (auto id : path)
                    r += std::to_string(id) + ".";
                if (r.size())
                    r.resize(r.size()-1);
                return r;
            

            bool empty() const   return path.empty(); 
            bool single() const  return path.size() == 1; 

            key_type reduce()   
                key_type res = path.front();
                path.pop_front();
                return res;
            
        ;
    ;
 

// Test code
using MetaStorageTree = boost::property_tree::basic_ptree<Framework::CommonClientServer::InterfaceID_t, std::string>;

void dump_tree_for_debug(MetaStorageTree const&);

int main() 
    MetaStorageTree tree;

    using Framework::CommonClientServer::InterfacePathChain_t;
    tree.put(InterfacePathChain_t0, "0");
    tree.put(InterfacePathChain_t0, 0, "1");
    tree.put(InterfacePathChain_t0, 1, "2");
    tree.put(InterfacePathChain_t0, 0, 0, "3");
    tree.put(InterfacePathChain_t0, 1, 0, "4");
    tree.put(InterfacePathChain_t0, 1, 1, "5");

    dump_tree_for_debug(tree);


// FOR DEBUG/DEMO PURPOSES:
#include <boost/property_tree/xml_parser.hpp>
#include <iostream>

template <typename WeirdTree, typename Path = typename WeirdTree::path_type>
boost::property_tree::ptree convert_weird_tree(WeirdTree const& weird) 
    boost::property_tree::ptree normal;

    if (auto v = weird.template get_value_optional<std::string>()) 
        normal.put_value(*v);
    

    for (auto& element : weird) 
        normal.add_child(Pathelement.first.dump(), convert_weird_tree(element.second));
    

    return normal;


void dump_tree_for_debug(MetaStorageTree const& tree) 
    write_xml(std::cout, convert_weird_tree(tree), boost::property_tree::xml_writer_make_settings<std::string>(' ', 2));

打印:

<?xml version="1.0" encoding="utf-8"?>
<0>
  0
  <0>
    1
    <0>3</0>
  </0>
  <1>
    2
    <0>4</0>
    <1>5</1>
  </1>
</0>

【讨论】:

感谢您的宝贵时间。这确实向我澄清了一些事情,但还没有完全清楚。 好吧。让我们知道您缺少什么。也许只是发布另一个关于它的有针对性的问题。 是的,我做到了。抱歉,当时忘记接受您的回答——太激动了。不幸的是,我发现无法在 boost::property_tree 中获取子节点的父节点(请参阅此问题Getting boost property_tree parent node,您也已回答)。这是必不可少的,所以我们不得不退出使用 boost::property_tree 并配置我们自己的。

以上是关于为自定义路径类型设置 boost property_tree的主要内容,如果未能解决你的问题,请参考以下文章

是否有办法在春季为自定义依赖项找出application.properties文件的属性名?

UIButton wierdness:无法为自定义按钮类型设置标题

FMT C++ 库:允许用户为自定义类型设置格式说明符

使用 QPropretyAnimation 为自定义 QGraphicsItem 设置动画

在 Wordpress 中,如何将自定义帖子类型的默认管理员排序顺序设置为自定义列?

使用 Boost 图形库:boost::mutable_queue 中的 property_map