현재 버전의 Boost.Property (1.55)는 차이점 등 mathematical relations을 직접 지원하지 않습니다. 그러나 트리를 반복하는 함수를 작성하고 노드의 전체 경로와 노드 자체가있는 사용자 제공 함수를 호출 할 수 있습니다. 각 반복은 노드의 전체 경로를 제공하므로 알고리즘은 access data으로 쉽게 수행 할 수 있으며 get()
, put()
또는 add()
으로 결과를 구성 할 수 있습니다. 예를 들어
여기 트리 반복 할 수있는 기능이다
/// @brief Walk a Boost.PropertyTree tree, invoking the binary function with
/// the full path and the current node.
template <typename Tree, typename Function>
void for_each(
const Tree& tree,
Function fn,
const typename Tree::path_type& parent_path = typename Tree::path_type())
{
using path_type = typename Tree::path_type;
for (auto&& value_pair: tree)
{
auto current_path = parent_path/path_type(value_pair.first);
fn(current_path, value_pair.second);
for_each(value_pair.second, fn, current_path);
}
}
및 알고리즘 차이 구성하는 반복 사용
/// @brief Return tree with elements in @ref s but not in @ref t.
template <typename Tree>
Tree tree_difference(const Tree& s, const Tree& t)
{
using data_type = typename Tree::data_type;
Tree result;
// Iterate 's', adding to the result when either a node in
// 't' is not present in 's' or the node's values differ.
for_each(s,
[&](const typename Tree::path_type& path, const Tree& node)
{
auto value = t.template get_optional<data_type>(path);
if (!value || (value.get() != node.data()))
result.add(path, node.data());
});
return result;
}
여기
가 complete example이다 그런 두 나무 사이의 차이를 보여줍니다. tree_difference()
이 정확한 결과를 제공하지 못하는 경우 확장 성을 입증하기 위해 결합, 교차 및 대칭 차이와 같은 다른 작업도 추가했습니다. 다음과 같은 출력을 생성
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/foreach.hpp>
#include <iostream>
namespace tree_ops {
/// @brief Walk a Boost.PropertyTree tree, invoking the binary function with
/// the full path and the current node.
template <typename Tree, typename Function>
void for_each(
const Tree& tree,
Function fn,
const typename Tree::path_type& parent_path = typename Tree::path_type())
{
using path_type = typename Tree::path_type;
for (auto&& value_pair: tree)
{
auto current_path = parent_path/path_type(value_pair.first);
fn(current_path, value_pair.second);
for_each(value_pair.second, fn, current_path);
}
}
/// @brief Return tree with elements in @ref s but not in @ref t.
template <typename Tree>
Tree tree_difference(const Tree& s, const Tree& t)
{
using data_type = typename Tree::data_type;
Tree result;
// Iterate 's', adding to the result when either a node in
// 't' is not present in 's' or the node's values differ.
for_each(s,
[&](const typename Tree::path_type& path, const Tree& node)
{
auto value = t.template get_optional<data_type>(path);
if (!value || (value.get() != node.data()))
result.add(path, node.data());
});
return result;
}
/// @brief Return tree with elements from both @ref s and @ref t.
template <typename Tree>
Tree tree_union(const Tree& s, const Tree& t)
{
// The result will always contain all values in @ref s.
Tree result = s;
// Iterate 't', add values to the result only if the node is
// either not in 's' or the values are different.
for_each(t,
[&](const typename Tree::path_type& path, const Tree& node)
{
auto child = s.get_child_optional(path);
if (!child || (child->data() != node.data()))
result.add(path, node.data());
});
return result;
}
/// @brief Return tree with elements common to @ref s and @ref t.
template <typename Tree>
Tree tree_intersection(const Tree& s, const Tree& t)
{
using data_type = typename Tree::data_type;
Tree result;
// Iterate 's', adding common elements found in 't' that have the same
// value.
for_each(s,
[&](const typename Tree::path_type& path, const Tree& node)
{
auto value = t.template get_optional<data_type>(path);
if (value && (value.get() == node.data()))
result.add(path, node.data());
});
return result;
}
/// @brief Return tree with elements in either @ref s or @ref t, but not
/// both.
template <typename Tree>
Tree tree_symmetric_difference(const Tree& s, const Tree& t)
{
return tree_difference(tree_union(s, t), tree_intersection(s, t));
}
} // namespace tree_ops
// Expose mathematical tree operations with operators.
/// @brief Return tree with elements in @ref lhs but not in @ref rhs.
boost::property_tree::ptree operator-(
const boost::property_tree::ptree& lhs,
const boost::property_tree::ptree& rhs)
{
return tree_ops::tree_difference(lhs, rhs);
}
/// @brief Return tree with elements in both @ref lhs and @ref rhs.
boost::property_tree::ptree operator|(
const boost::property_tree::ptree& lhs,
const boost::property_tree::ptree& rhs)
{
return tree_ops::tree_union(lhs, rhs);
}
/// @brief Return tree with elements common to @ref lhs and @ref rhs.
boost::property_tree::ptree operator&(
const boost::property_tree::ptree& lhs,
const boost::property_tree::ptree& rhs)
{
return tree_ops::tree_intersection(lhs, rhs);
}
/// @brief Return tree with elements in either @ref lhs or @ref rhs, but not
/// both.
boost::property_tree::ptree operator^(
const boost::property_tree::ptree& lhs,
const boost::property_tree::ptree& rhs)
{
return tree_ops::tree_symmetric_difference(lhs, rhs);
}
int main()
{
std::istringstream json1_stream {
"{"
" \"node1\" : 1,"
" \"node_that_only_appears_in_this_one\" : 2,"
" \"node3\" :"
" {"
" \"nested1\" : 3,"
" \"nested2\" :"
" {"
" \"double_nested1\" : 5,"
" \"double_nested2\" : \"foo\""
" }"
" }"
"}"};
std::istringstream json2_stream {
"{"
" \"node1\" : 1,"
" \"node3\" :"
" {"
" \"nested1\" : 3,"
" \"nested_that_only_appears_in_this_one\" : 5,"
" \"nested2\" :"
" {"
" \"double_nested1\" : 5,"
" \"double_nested2\" : \"bar\""
" }"
" }"
"}"};
boost::property_tree::ptree tree1, tree2;
read_json(json1_stream, tree1);
read_json(json2_stream, tree2);
std::cout << "difference in tree2 and tree1:\n";
write_json(std::cout, tree2 - tree1);
std::cout << "union of tree1 and tree2:\n";
write_json(std::cout, tree1 | tree2);
std::cout << "intersection of tree1 and tree2:\n";
write_json(std::cout, tree1 & tree2);
std::cout << "symmetric difference of tree1 and tree2:\n";
write_json(std::cout, tree1^tree2);
}
:
difference in tree2 and tree1:
{
"node3":
{
"nested_that_only_appears_in_this_one": "5",
"nested2":
{
"double_nested2": "bar"
}
}
}
union of tree1 and tree2:
{
"node1": "1",
"node_that_only_appears_in_this_one": "2",
"node3":
{
"nested1": "3",
"nested2":
{
"double_nested1": "5",
"double_nested2": "foo",
"double_nested2": "bar"
},
"nested_that_only_appears_in_this_one": "5"
}
}
intersection of tree1 and tree2:
{
"node1": "1",
"node3":
{
"nested1": "3",
"nested2":
{
"double_nested1": "5"
}
}
}
symmetric difference of tree1 and tree2:
{
"node_that_only_appears_in_this_one": "2",
"node3":
{
"nested2":
{
"double_nested2": "foo",
"double_nested2": "bar"
},
"nested_that_only_appears_in_this_one": "5"
}
}
참고 : get_child()
가 직접 또는 간접적으로 사용되는 것처럼 나무가 중복 키가있는 경우, 그 결과가 결정되지 않을 수 있습니다.
경로에 따라 각 레벨의 결과가 완전히 일치하지 않을 수도 있습니다. 즉, 동일한 키가 여러 번 나타나는 경우 선택되는 자식이 지정되지 않은 것입니다. 이 경로가있는 하위 항목이 있더라도 해결되지 않는 경로로 이어질 수 있습니다. 예 :
* a -> b -> c
* -> b
*
경로 "A.B.C", "B"의 해상도가 최초의 노드를 선택하면 성공하지만 제를 선택하는 경우 실패 할 것이다.
알고리즘 구현이 완료되면 두 개의 트리를 모두 반복하여 중복 키를 지원하는 중간 데이터 구조를 채울 필요가 있습니다. 그런 다음 중간 데이터 구조에 대해 작업을 수행하고 트리를 결과로 구성합니다.
이것은 매우 친절합니다. 감사합니다! 1.64 향상과 차이점이나 차이점이 부족합니까? – Gizmo
그래서 이것은 실제로'<사용자 아이디 = "2"> ADMIN <사용자 아이디 = "3"> NOTADMIN ', 결과 DIFF의 변화, 어떤 생각으로 NOTADMIN를보고하는 방법이 문제를 해결하려면 실패? –
Gizmo