I have the following XML file and I want to store it using the below structures.
the data structs:
struct transitions
{
string oldstate;
string event;
string newstate;
};
struct XML_Diagram
{
string diag_name;
string diag_defaultstate;
list<string> diag_states;
list<string> diag_events;
list<transitions> diag_transitions;
};
the xml file:
<diagram>
<diagname>DiagaX</diagname>
<states>
<state>A</state>
.............
</states>
<events>
<event>ev1</event>
.................
</events>
<defaultstate>A</defaultstate>
<transitions>
<transition>
<oldstate>A</oldstate>
<event>ev1</event>
<newstate>B</newstate>
</transition>
<transition>
<oldstate>B</oldstate>
<event>ev2</event>
<newstate>C</newstate>
</transition>
.........................
</transitions>
</diagram>
It is clear to me how can I to access diagram.states . I can do it with the folowing code:
using boost::property_tree::ptree;
ptree pt;
// Get diagram states
BOOST_FOREACH(ptree::value_type &v, pt.get_child("diagram.states"))
{
diag_states.push_back(v.second.data());
}
What is not clear to me is how can I access the data from at the level diagram.transitions.transition ?
My problem is that I could not find any examples in the documentation on how to parse more complex xml files with several levels.
This useful utility function traverses and pretty-prints an entire property tree:
using boost::property_tree::ptree;
std::string q(const std::string& s) { return "\"" + s + "\""; }
void print_tree(const ptree& pt, int level)
{
const std::string sep(2 * level, ' ');
BOOST_FOREACH(const ptree::value_type &v, pt) {
std::cout
<< sep
<< q(v.first) << " : " << q(v.second.data()) << "\n";
print_tree(v.second, level + 1);
}
}
void print_tree(const ptree& pt) { print_tree(pt, 0); }
The v.second
values are trees themselves that can be accessed with the usual get
methods. The transitions
can for example be accessed and printed like this:
using std::string;
void print_transitions(const ptree& pt)
{
BOOST_FOREACH(
const ptree::value_type &v,
pt.get_child("diagram.transitions"))
{
const ptree& child = v.second;
std::cout
<< "Event "
<< child.get<string>("event")
<< " in state "
<< child.get<string>("oldstate")
<< " leads to state "
<< child.get<string>("newstate")
<< "\n";
}
}
Here is another example of how to print ptree
with attributes:
namespace pt = boost::property_tree;
// worker
typedef std::pair<const pt::ptree&, unsigned> tree_printer;
// empty ptree helper
const pt::ptree& empty_ptree()
{
static pt::ptree t;
return t;
}
std::ostream& operator <<(std::ostream& os, const tree_printer& p)
{
const pt::ptree& tree = p.first;
if(tree.empty()) return os;
const std::string indent(p.second, ' ');
BOOST_FOREACH(const pt::ptree::value_type& v, tree)
{
const std::string& nodeName = v.first;
if(nodeName == "<xmlattr>") continue;
os << indent << nodeName;
const pt::ptree& attributes =
v.second.get_child("<xmlattr>", empty_ptree());
if(!attributes.empty())
{
os << " [ ";
BOOST_FOREACH(const pt::ptree::value_type& attr, attributes)
{
const std::string& attrName = attr.first;
const std::string& attrVal = attr.second.data();
os << attrName << " = '" << attrVal << "'; ";
}
os << "]";
}
os << "\n";
const pt::ptree& childNode = v.second;
os << tree_printer(childNode, p.second + 1);
}
return os;
}
std::ostream& operator <<(std::ostream& os, const pt::ptree& tree)
{
os << tree_printer(tree, 0);
return os;
}
Hope this helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With