如何使用 boost::property_tree 和 put_value(const Type &value) 修改节点元素
How to modify node element with boost::property_tree and put_value(const Type &value)
我是 boost::property_tree
的新手,我在完成本应是一项简单任务时遇到了一些麻烦。
我有一个默认的 xml 文件,该文件将被复制并通过下面的 ptree & modelModifier(...)
函数传入的参数使其唯一。我想要做的就是将 xml 解析为一个 ptree,然后将 name
字段(除其他外,但让我们从 name
开始)从“默认”修改为任何名称从 object_name
变量传入,然后将其写回原始 ptree。
函数 pTreeIterator
只是遍历每个子项并显示其内容。
xml
<?xml version='1.0'?>
<sdf version='1.7'>
<model name='default'>
<link name='link'>
<inertial>
<mass>3.14999</mass>
<inertia>
<ixx>2.86712</ixx>
<ixy>0</ixy>
<ixz>0</ixz>
<iyy>2.86712</iyy>
<iyz>0</iyz>
<izz>0.524998</izz>
</inertia>
<pose>0 0 0 0 -0 0</pose>
</inertial>
</link>
</model>
</sdf>
代码
void ptreeIterator(ptree & pt)
{
using boost::property_tree::ptree;
for (auto&it : pt)
{
std::cout << __FUNCTION__ << std::endl;
std::cout << "------------------------------------------------------" << std::endl;
std::cout << "Iteration output: " << std::endl;
std::cout << "1: pt1: " << it.first << std::endl;
if(pt.get_child_optional(it.first))
{
cout << "pt.get_child_optional(it.first) ---> " << it.first << endl;
ptree pt2 = pt.get_child(it.first);
for (auto&it2 : pt2)
{
std::cout << "\t2: " << "pt2: " << it2.first << " :: " << (std::string)it2.second.data() << std::endl;
if(pt2.get_child_optional(it2.first))
{
ptree pt3 = pt2.get_child(it2.first);
for (auto&it3 : pt3)
{
std::cout << "\t\t3: " << "pt3: " << it3.first << " :: " << (std::string)it3.second.data() << std::endl;
}
}
}
}
}
}
ptree & modelModifier(ptree &model, double px, double py, std::string object_name, uint16_t height)
{
for(auto &it:model){
cout << "it.first = " << it.first << endl;
if(it.first=="model"){
cout << "MODEL TAG" << endl;
model.put_value(object_name);
}
ptreeIterator(model);
}
}
int main(){
ptree ptModel;
const string filenameToInsert = "model.sdf";
std::ifstream ifsModel(filenameToInsert,std::ifstream::binary);
read_xml(ifsModel, ptModel, boost::property_tree::xml_parser::trim_whitespace);
modelModifier(ptModel, 0, 0, "TEST1234567", 30);
return 0;
}
输出
it.first = model
it.second.data()
ptreeIterator
------------------------------------------------------
Iteration output:
1: pt1: model
pt.get_child_optional(it.first) ---> model
2: pt2: <xmlattr> ::
3: pt3: name :: default
预期输出
it.first = model
it.second.data()
ptreeIterator
------------------------------------------------------
Iteration output:
1: pt1: model
pt.get_child_optional(it.first) ---> model
2: pt2: <xmlattr> ::
3: pt3: name :: TEST1234567
首先,您的代码有 UB,因为 modelModifier
没有 return 值。
(std::string)it2.second.data()
中的 C 风格强制转换非常危险,因为它有 reinterpret_cast
-ing 不相关类型的风险。这种生硬的铸造没有任何理由。只需删除演员!
此外,ptreeIterator
应该取 ptree const&
,而不是 ptree&
。
修复这些问题后,示例不会显示您声明的输出,而是打印 (Live On Coliru)
it.first = sdf
ptreeIterator
------------------------------------------------------
Iteration output:
1: pt1: sdf
pt.get_child_optional(it.first) ---> sdf
2: pt2: <xmlattr> ::
3: pt3: version :: 1.7
2: pt2: model ::
3: pt3: <xmlattr> ::
3: pt3: link ::
现在,即使在您的问题输出中,您也可以清楚地看到 model
节点及其名称属性之间的区别,这显然是您想要修改的。只需编写代码即可访问:
it.second.get_child("<xmlattr>.name").put_value(object_name);
This would be correct, assuming that the attribute always exists and instead of ptModel
you pass ptModel.get_child("sdf")
to modifyModel
).
其他注意事项:简化!
也就是说,请简化整个事情!
ptree pt2 = pt.get_child(it.first);
应该是这样的
ptree const& pt2 = it.second;
和
- 只用
get_child_optional
重复get_child
更浪费
- 好的做法是将 output/query 和突变分开。所以不要从
modelModifier
内部调用 ptreeIterator
- 另外,给函数起一个很好的描述性名称(这样你就不会不好意思地解释“函数
pTreeIterator
只是遍历每个子项并显示其内容” - 只需将其命名为 displayModel
?)
- 与其煞费苦心(而且有缺陷)迭代特定模型并以非常混乱的定制方式打印它,只需使用
write_xml
/write_info
/write_json
以可靠的方式转储它方式。
列表
namespace Model {
void display(ptree const& pt)
{
write_json(std::cout << __FUNCTION__ << "\n---------------\n", pt);
}
void modify(ptree& model, double, double, std::string object_name, uint16_t)
{
for (auto& it : model) {
std::cout << "root = " << it.first << std::endl;
it.second.get_child("model.<xmlattr>.name").put_value(object_name);
}
}
}
版画
root = sdf
display
---------------
{
"sdf": {
"<xmlattr>": {
"version": "1.7"
},
"model": {
"<xmlattr>": {
"name": "TEST1234567"
},
"link": {
"<xmlattr>": {
"name": "link"
},
"inertial": {
"mass": "3.14999",
"inertia": {
"ixx": "2.86712",
"ixy": "0",
"ixz": "0",
"iyy": "2.86712",
"iyz": "0",
"izz": "0.524998"
},
"pose": "0 0 0 0 -0 0"
}
}
}
}
}
奖金
在 name 属性可能不存在的情况下,以下代码将即时创建它:
void modify(ptree& model, double, double, std::string object_name, uint16_t)
{
ptree value;
value.put_value(object_name);
for (auto& it : model) {
std::cout << "root = " << it.first << std::endl;
it.second.put_child("model.<xmlattr>.name", value);
}
}
我是 boost::property_tree
的新手,我在完成本应是一项简单任务时遇到了一些麻烦。
我有一个默认的 xml 文件,该文件将被复制并通过下面的 ptree & modelModifier(...)
函数传入的参数使其唯一。我想要做的就是将 xml 解析为一个 ptree,然后将 name
字段(除其他外,但让我们从 name
开始)从“默认”修改为任何名称从 object_name
变量传入,然后将其写回原始 ptree。
函数 pTreeIterator
只是遍历每个子项并显示其内容。
xml
<?xml version='1.0'?>
<sdf version='1.7'>
<model name='default'>
<link name='link'>
<inertial>
<mass>3.14999</mass>
<inertia>
<ixx>2.86712</ixx>
<ixy>0</ixy>
<ixz>0</ixz>
<iyy>2.86712</iyy>
<iyz>0</iyz>
<izz>0.524998</izz>
</inertia>
<pose>0 0 0 0 -0 0</pose>
</inertial>
</link>
</model>
</sdf>
代码
void ptreeIterator(ptree & pt)
{
using boost::property_tree::ptree;
for (auto&it : pt)
{
std::cout << __FUNCTION__ << std::endl;
std::cout << "------------------------------------------------------" << std::endl;
std::cout << "Iteration output: " << std::endl;
std::cout << "1: pt1: " << it.first << std::endl;
if(pt.get_child_optional(it.first))
{
cout << "pt.get_child_optional(it.first) ---> " << it.first << endl;
ptree pt2 = pt.get_child(it.first);
for (auto&it2 : pt2)
{
std::cout << "\t2: " << "pt2: " << it2.first << " :: " << (std::string)it2.second.data() << std::endl;
if(pt2.get_child_optional(it2.first))
{
ptree pt3 = pt2.get_child(it2.first);
for (auto&it3 : pt3)
{
std::cout << "\t\t3: " << "pt3: " << it3.first << " :: " << (std::string)it3.second.data() << std::endl;
}
}
}
}
}
}
ptree & modelModifier(ptree &model, double px, double py, std::string object_name, uint16_t height)
{
for(auto &it:model){
cout << "it.first = " << it.first << endl;
if(it.first=="model"){
cout << "MODEL TAG" << endl;
model.put_value(object_name);
}
ptreeIterator(model);
}
}
int main(){
ptree ptModel;
const string filenameToInsert = "model.sdf";
std::ifstream ifsModel(filenameToInsert,std::ifstream::binary);
read_xml(ifsModel, ptModel, boost::property_tree::xml_parser::trim_whitespace);
modelModifier(ptModel, 0, 0, "TEST1234567", 30);
return 0;
}
输出
it.first = model
it.second.data()
ptreeIterator
------------------------------------------------------
Iteration output:
1: pt1: model
pt.get_child_optional(it.first) ---> model
2: pt2: <xmlattr> ::
3: pt3: name :: default
预期输出
it.first = model
it.second.data()
ptreeIterator
------------------------------------------------------
Iteration output:
1: pt1: model
pt.get_child_optional(it.first) ---> model
2: pt2: <xmlattr> ::
3: pt3: name :: TEST1234567
首先,您的代码有 UB,因为 modelModifier
没有 return 值。
(std::string)it2.second.data()
中的 C 风格强制转换非常危险,因为它有 reinterpret_cast
-ing 不相关类型的风险。这种生硬的铸造没有任何理由。只需删除演员!
此外,ptreeIterator
应该取 ptree const&
,而不是 ptree&
。
修复这些问题后,示例不会显示您声明的输出,而是打印 (Live On Coliru)
it.first = sdf
ptreeIterator
------------------------------------------------------
Iteration output:
1: pt1: sdf
pt.get_child_optional(it.first) ---> sdf
2: pt2: <xmlattr> ::
3: pt3: version :: 1.7
2: pt2: model ::
3: pt3: <xmlattr> ::
3: pt3: link ::
现在,即使在您的问题输出中,您也可以清楚地看到 model
节点及其名称属性之间的区别,这显然是您想要修改的。只需编写代码即可访问:
it.second.get_child("<xmlattr>.name").put_value(object_name);
This would be correct, assuming that the attribute always exists and instead of
ptModel
you passptModel.get_child("sdf")
tomodifyModel
).
其他注意事项:简化!
也就是说,请简化整个事情!
ptree pt2 = pt.get_child(it.first);
应该是这样的
ptree const& pt2 = it.second;
和
- 只用
get_child_optional
重复get_child
更浪费 - 好的做法是将 output/query 和突变分开。所以不要从
modelModifier
内部调用 - 另外,给函数起一个很好的描述性名称(这样你就不会不好意思地解释“函数
pTreeIterator
只是遍历每个子项并显示其内容” - 只需将其命名为displayModel
?) - 与其煞费苦心(而且有缺陷)迭代特定模型并以非常混乱的定制方式打印它,只需使用
write_xml
/write_info
/write_json
以可靠的方式转储它方式。
ptreeIterator
列表
namespace Model {
void display(ptree const& pt)
{
write_json(std::cout << __FUNCTION__ << "\n---------------\n", pt);
}
void modify(ptree& model, double, double, std::string object_name, uint16_t)
{
for (auto& it : model) {
std::cout << "root = " << it.first << std::endl;
it.second.get_child("model.<xmlattr>.name").put_value(object_name);
}
}
}
版画
root = sdf
display
---------------
{
"sdf": {
"<xmlattr>": {
"version": "1.7"
},
"model": {
"<xmlattr>": {
"name": "TEST1234567"
},
"link": {
"<xmlattr>": {
"name": "link"
},
"inertial": {
"mass": "3.14999",
"inertia": {
"ixx": "2.86712",
"ixy": "0",
"ixz": "0",
"iyy": "2.86712",
"iyz": "0",
"izz": "0.524998"
},
"pose": "0 0 0 0 -0 0"
}
}
}
}
}
奖金
在 name 属性可能不存在的情况下,以下代码将即时创建它:
void modify(ptree& model, double, double, std::string object_name, uint16_t)
{
ptree value;
value.put_value(object_name);
for (auto& it : model) {
std::cout << "root = " << it.first << std::endl;
it.second.put_child("model.<xmlattr>.name", value);
}
}