为自定义路径类型设置 boost property_tree
Setting up boost property_tree for a custom path type
我需要在我的程序中使用 boost::property_tree。现在我很难弄清楚如何将它与自定义路径类型一起使用。我想要的路径类型是 Framework::CommonClientServer::InterfacePathChain_t
它的类型定义是这样的:
typedef std::vector<InterfaceID_t> InterfacePathChain_t;
typedef int InterfaceID_t;
所以基本上路径类型应该是std::vector<int>
。
例如:
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} 所以它应该是 node1 的子节点)似乎没有被添加。当我尝试遍历树时,会发生这种情况:
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 中我需要的所有内容进行 typedef 时做错了,但是找不到关于该主题的任何足够信息,因为 property_tree 的大部分使用都是专用的JSON 解析所以使用标准 std::string 路径类型。
我认为逻辑上的误解是其根源。您实际上并没有特化一棵树来使用另一种路径类型。
你将它专门化为另一个 key_type
(在这种情况下,你希望它是 InterfaceID_t
)。查询中使用的路径类型仅隐式派生,从不存储。
因此路径类型不能 "be" InterfacePathChain_t
,因为它必须是 path_of<key_type>::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_t{0}, "0");
tree.put(InterfacePathChain_t{0, 0}, "1");
tree.put(InterfacePathChain_t{0, 1}, "2");
tree.put(InterfacePathChain_t{0, 0, 0}, "3");
tree.put(InterfacePathChain_t{0, 1, 0}, "4");
tree.put(InterfacePathChain_t{0, 1, 1}, "5");
dump_tree_for_debug(tree);
}
我选择使用 deque<int>
来实现 path_of<int>::type
,这对任务来说更自然,并强调了它 NOT 需要与 InterfacePathChain_t
.
相同
我将输出添加到 XML;但是,PropertyTree 的序列化后端假定 path_type::value_type
是有效的流字符类型。由于您选择的树专业化不是这种情况,因此我在标准 ptree
.
的 convert_weird_tree
添加了一个辅助函数
#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_t{0}, "0");
tree.put(InterfacePathChain_t{0, 0}, "1");
tree.put(InterfacePathChain_t{0, 1}, "2");
tree.put(InterfacePathChain_t{0, 0, 0}, "3");
tree.put(InterfacePathChain_t{0, 1, 0}, "4");
tree.put(InterfacePathChain_t{0, 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(Path{element.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。现在我很难弄清楚如何将它与自定义路径类型一起使用。我想要的路径类型是 Framework::CommonClientServer::InterfacePathChain_t
它的类型定义是这样的:
typedef std::vector<InterfaceID_t> InterfacePathChain_t;
typedef int InterfaceID_t;
所以基本上路径类型应该是std::vector<int>
。
例如:
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} 所以它应该是 node1 的子节点)似乎没有被添加。当我尝试遍历树时,会发生这种情况:
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 中我需要的所有内容进行 typedef 时做错了,但是找不到关于该主题的任何足够信息,因为 property_tree 的大部分使用都是专用的JSON 解析所以使用标准 std::string 路径类型。
我认为逻辑上的误解是其根源。您实际上并没有特化一棵树来使用另一种路径类型。
你将它专门化为另一个 key_type
(在这种情况下,你希望它是 InterfaceID_t
)。查询中使用的路径类型仅隐式派生,从不存储。
因此路径类型不能 "be" InterfacePathChain_t
,因为它必须是 path_of<key_type>::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_t{0}, "0");
tree.put(InterfacePathChain_t{0, 0}, "1");
tree.put(InterfacePathChain_t{0, 1}, "2");
tree.put(InterfacePathChain_t{0, 0, 0}, "3");
tree.put(InterfacePathChain_t{0, 1, 0}, "4");
tree.put(InterfacePathChain_t{0, 1, 1}, "5");
dump_tree_for_debug(tree);
}
我选择使用
deque<int>
来实现path_of<int>::type
,这对任务来说更自然,并强调了它 NOT 需要与InterfacePathChain_t
. 相同
我将输出添加到 XML;但是,PropertyTree 的序列化后端假定
path_type::value_type
是有效的流字符类型。由于您选择的树专业化不是这种情况,因此我在标准ptree
. 的
convert_weird_tree
添加了一个辅助函数
#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_t{0}, "0");
tree.put(InterfacePathChain_t{0, 0}, "1");
tree.put(InterfacePathChain_t{0, 1}, "2");
tree.put(InterfacePathChain_t{0, 0, 0}, "3");
tree.put(InterfacePathChain_t{0, 1, 0}, "4");
tree.put(InterfacePathChain_t{0, 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(Path{element.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>