It seems like a really useless thing to do.
A property tree is /already/ that "structured map":
auto po = pt.get_child("purchaseOrder");
std::cout << "items.item.Price.USPrice: '" << po.get("items.item.Price.USPrice", "") << "'
";
If you want XPath, use an XPath capable XML library (What XML parser should I use in C++?).
If you want easier access, write some translators or access functions. But whatever you do, you probably do not wish to through the structural information away, as your question kind of suggests.
Here's a sample of something I'd find useful:
Live On Coliru
#include <boost/property_tree/xml_parser.hpp>
#include <boost/multiprecision/cpp_dec_float.hpp>
#include <iostream>
#include <map>
using Decimal = boost::multiprecision::cpp_dec_float_50;
using Tree = boost::property_tree::ptree;
namespace BackOffice {
struct purchaseOrder {
struct address {
std::string country, name, street, city, state, zip;
} shipTo, billTo;
std::string comment;
struct item {
std::string partNum, productName, comment;
size_t quantity;
struct Price {
Decimal USPrice, UKPrice;
} price;
};
std::vector<item> items;
};
void read_tree(Tree const& tree, purchaseOrder::address& into);
void read_tree(Tree const& tree, purchaseOrder::item::Price& into);
void read_tree(Tree const& tree, purchaseOrder::item& into);
void read_tree(Tree const& tree, purchaseOrder& into);
template <typename T, typename Indirect>
void read_tree(Indirect const& maybeTree, T& into, decltype(&*maybeTree) = nullptr) {
if (maybeTree) read_tree(*maybeTree, into); else into = {};
}
template <typename T, typename Indirect>
void read_tree(Indirect const& maybeTree, std::string sub, T& into, decltype(&*maybeTree) = nullptr) {
if (maybeTree) read_tree(*maybeTree, sub, into); else into = {};
}
template <typename T>
void read_tree(Tree const& tree, std::string sub, std::vector<T>& into) {
for (auto& child : tree) {
if (child.first == sub) {
into.emplace_back();
read_tree(child.second, into.back());
}
}
}
void read_tree(Tree const& tree, purchaseOrder::address& into) {
into.country = tree.get("<xmlattr>.country", "(unknown");
into.name = tree.get("name", "(unknown");
into.street = tree.get("street", "(unknown");
into.city = tree.get("city", "(unknown");
into.state = tree.get("state", "(unknown");
into.zip = tree.get("zip", "(unknown");
}
void read_tree(Tree const& tree, purchaseOrder::item::Price& into) {
into.UKPrice = tree.get("UKPrice", Decimal{});
into.USPrice = tree.get("USPrice", Decimal{});
}
void read_tree(Tree const& tree, purchaseOrder::item& into) {
into.partNum = tree.get("<xmlattr>.partNum", "(unknown");
into.productName = tree.get("productName", "(unknown");
into.comment = tree.get("comment", "");
read_tree(tree.get_child_optional("Price"), into.price);
}
void read_tree(Tree const& tree, purchaseOrder& into) {
read_tree(tree.get_child_optional("shipTo"), into.shipTo);
read_tree(tree.get_child_optional("billTo"), into.billTo);
read_tree(tree.get_child_optional("items"), "item", into.items);
into.comment = tree.get("comment", "");
}
}
int main() {
Tree pt;
read_xml( "input.txt", pt);
//auto po = pt.get_child("purchaseOrder");
//std::cout << "items.item.Price.USPrice: '" << po.get("items.item.Price.USPrice", "") << "'
";
BackOffice::purchaseOrder po;
read_tree(pt.get_child("purchaseOrder"), po);
}