I am want to parse below xml structure using boost property_tree.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Txn ver="1.0">
<TOpts tCount="1" tformat="0" ttimeout="10" />
<TData>
<Tvalue date="YYMMDD" time="HHMM" Ref="100"/>
</TData>
<TCustOpts>
<Param name="SALE" value="xyz" />
</TCustOpts>
</Txn>
I am able to parse, first Topts
field of above xml, But for TData
& TCustOpts
field, I am not getting right iteration and approach to parse the xml and facing exception. Can someone provide me right approach for TData
& TCustOpts
field parsing.
Below is my code for reference.
stringstream ssString;
boost::property_tree::ptree pt1;
ssString << xml;
boost::property_tree::read_xml(ssString, pt1);
string TxnVer = pt1.get<string>("Txn.<xmlattr>.ver");
boost::property_tree::ptree formats = pt1.get_child("Txn");
BOOST_FOREACH(boost::property_tree::ptree::value_type const& node, formats) {
if (node.first == "TOpts") {
const boost::property_tree::ptree & attributes = node.second.get_child("<xmlattr>");
BOOST_FOREACH(boost::property_tree::ptree::value_type const& v, attributes) {
if (v.first == "tCount") {
std::cout << " tCount " << v.second.data() << endl;
}
else if (v.first == "tformat") {
std::cout << " tformat" << v.second.data() << endl;
}
else if (v.first == "ttimeout") {
std::cout << " ttimeout " << v.second.data() << endl;
}
}
}
else if (node.first == "TOpts")
else if (node.first == "TCustOpts") {
const boost::property_tree::ptree & attributes1 = node.second.get_child("<xmlattr>");
BOOST_FOREACH(boost::property_tree::ptree::value_type const& s, attributes1) {
if (s.first == "name"){
std::cout << "name " << s.second.data() << endl;
}
else if (s.first == "value") {
std::cout << "value " << s.second.data() << endl;
}
}
}
}
Ok, the usual anti-pattern when using Property Tree to parse information is "loop frenzy".
The whole idea of storing key-value pairs in a tree format is to avoid having to loop low-level structures, instead using convenient addressing (using paths).
Another anti-pattern is to have all the parsing in one big function. I'd split things up.
Define Some Data Types
Let's start with defining some data-types to keep our data manageable:
This is our make-shift "Domain Layer".
Let's Parse!
So, here's how I'd write the parsing code:
The only not-so-straight-forward thing is
parse_optional
to deal with subtrees that might be absent.Using it:
BONUS: Roundtrip
Let's also save the same "Domain" classes back to a property tree, so we can verify it works:
FULL DEMO
This demo shows your original XML parsed and serialized back:
Live On Coliru
Which prints: