I want to put a new value to a child inside a ptree via path (no iteration)
As example:
#include <iostream>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
int main() {
using boost::property_tree::ptree;
ptree main;
ptree children;
children.add("Foo", "bar");
main.add_child("child", children);
main.add_child("child", children);
ptree newChildren("Foo");
main.put("child{2}.Foo", newChildren.data()); // <-- Access second element?
// Output
boost::property_tree::xml_writer_settings<std::string> settings('\t', 1);
boost::property_tree::write_xml(std::cout, main, settings);
std::cin.ignore();
return 0;
}
The problem is, I can´t access the second child via the path. Is there any formatting which work?
I mean this {2} part:
"child{2}.Foo"
I tried <2>, [2], (2)... no luck... :(
Any hope for me? Thank you!
I will repeat: there is no xml parser/library in Boost.
What you are (ab)using is Boost Property Tree. As you found, it's a "property tree" library, meaning it can do some things. Including writing and reading property trees.
If you want general purpose XML stuff, consider using an XML library (What XML parser should I use in C++?).
Without further ado:
#include <iostream>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
int main() {
using boost::property_tree::ptree;
ptree pt;
{
ptree children; children.add("Foo", "bar");
pt.add_child("child", children);
pt.add_child("child", children).put("MARK","so we know it's the second");
}
// Output
boost::property_tree::xml_writer_settings<std::string> settings('\t', 1);
//boost::property_tree::write_xml(std::cout, pt, settings);
auto child1 = std::find_if(pt.begin(), pt.end(), [](auto& node) { return node.first == "child"; });
auto child2 = std::find_if(std::next(child1), pt.end(), [](auto& node) { return node.first == "child"; });
if (child2 != pt.end())
{
boost::property_tree::write_xml(std::cout, child2->second, settings);
ptree newChildren("Foo");
child2->second.put("Sub.Foo", newChildren.data()).put("BYE", "ALL DONE"); // <-- Access second element?
boost::property_tree::write_xml(std::cout << "\n\nAFTER EDITING:\n", child2->second, settings);
}
}
Prints:
<?xml version="1.0" encoding="utf-8"?>
<Foo>bar</Foo>
<MARK>so we know it's the second</MARK>
AFTER EDITING:
<?xml version="1.0" encoding="utf-8"?>
<Foo>bar</Foo>
<MARK>so we know it's the second</MARK>
<Sub>
<Foo>
Foo
<BYE>ALL DONE</BYE>
</Foo>
</Sub>
Improving the style with a helper function:
#include <iostream>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
template <typename Tree, typename Out>
Out find_all(Tree& pt, typename Tree::path_type path, Out out) {
if (path.empty()) {
*out++ = pt;
return out;
}
auto head = path.reduce();
for (auto& child : pt)
if (child.first == head)
out = find_all(child.second, path, out);
return out;
}
int main() {
using boost::property_tree::ptree;
ptree pt;
{
ptree children; children.add("Foo", "bar");
pt.add_child("child", children);
pt.add_child("child", children).put("MARK","so we know it's the second");
}
// Output
boost::property_tree::xml_writer_settings<std::string> settings('\t', 1);
//boost::property_tree::write_xml(std::cout, pt, settings);
std::vector<std::reference_wrapper<ptree> > matches;
find_all(pt, "child", back_inserter(matches));
ptree& child2 = matches.at(1);
child2.put("BYE", "ALL DONE");
boost::property_tree::write_xml(std::cout, child2, settings);
}
Prints
<?xml version="1.0" encoding="utf-8"?>
<Foo>bar</Foo>
<MARK>so we know it's the second</MARK>
<BYE>ALL DONE</BYE>