my c++ code as below, and I want to use Doxygen produce xml file.
// c++ code
struct TestStru
{
struct{
int a;
} m_stru;
union{
int b;
char c;
} m_union;
int d;
};
The real output xml as follows, I omitted some information not important. My question is how to distinguish members in anonymous struct or union like 'a' from xml, or how could I configure Doxygen to achieve this.
<memberdef kind="variable" id="struct_test_stru_1a898ff9a1bccfc215accd3da2db864509" prot="public" static="no" mutable="no">
<type>int</type>
<definition>int TestStru::a</definition>
<argsstring></argsstring>
<name>a</name>
</memberdef>
<memberdef kind="variable" id="struct_test_stru_1aeca04a3d70feb1cef125df66625487ef" prot="public" static="no" mutable="no">
<type>struct TestStru::#0</type>
<definition>struct TestStru::#0 TestStru::m_stru</definition>
<argsstring></argsstring>
<name>m_stru</name>
</memberdef>
<memberdef kind="variable" id="struct_test_stru_1a2831fb7fc8f16abb913fe9a3c1fae19a" prot="public" static="no" mutable="no">
<type>int</type>
<definition>int TestStru::b</definition>
<argsstring></argsstring>
<name>b</name>
</memberdef>
<memberdef kind="variable" id="struct_test_stru_1aaa51d26f2195dcfdb0ce8f500275221b" prot="public" static="no" mutable="no">
<type>char</type>
<definition>char TestStru::c</definition>
<argsstring></argsstring>
<name>c</name>
</memberdef>
<memberdef kind="variable" id="struct_test_stru_1a547ce77ff0347d5a14ac43e078964022" prot="public" static="no" mutable="no">
<type>union TestStru::#1</type>
<definition>union TestStru::#1 TestStru::m_union</definition>
</memberdef>
<memberdef kind="variable" id="struct_test_stru_1a5437512aa23a668c8e10865521c35f7c" prot="public" static="no" mutable="no">
<type>int</type>
<definition>int TestStru::d</definition>
<argsstring></argsstring>
<name>d</name>
</memberdef>
Related
I have a piece of code that iterates over a boost property tree (XML).
I need a ptree of the current node, not the children of the node.
UPDATE
xml tree
<node id="A.html">
<subnode> child A1 </subnode>
<subnode> child A2 </subnode>
</node>
<node id="B.html">
<subnode> child B1 </subnode>
<subnode> child B2 </subnode>
</node>
itteration code
void parse_tree(ptree& pt, std::string key)
{
string nkey;
if (!key.empty())
nkey = key + ".";
ptree::const_iterator end = pt.end();
for(ptree::iterator it = pt.begin(); it != end; ++it){
//if the node's id is a .html filname, save the node to file
string id = it->second.get("<xmlattr>.id","");
if(id.find("B.html") != std::string::npos){ //Let's just test for "B.html"
write_xml("test.html", pt); //saves entire tree
write_xml("test.html", it->second); //saves only children of the node
}
parse_tree(it->second, nkey + it->first); //recursion
}
}
Results using write_xml("test.html", pt)
(We get the entire tree, we only want the node)
<node id="A.html">
<subnode> child A1 </subnode>
<subnode> child A2 </subnode>
</node>
<node id="B.html">
<subnode> child B1 </subnode>
<subnode> child B2 </subnode>
</node>
Results using write_xml("test.html", it->second)
(We have no parent node.. only child nodes)
<subnode> child B1 </subnode>
<subnode> child B2 </subnode>
Desired result
(We want the node, and it's children,.. like so)
<node id="B.html">
<subnode> child B1 </subnode>
<subnode> child B2 </subnode>
</node>
UPDATE 2
Rewritten in response to the comment/updated question.
There are two ways.
You can use the undocumented function write_xml_element to write the single element (using the key as element name):
// write the single element: (undocumented API)
boost::property_tree::xml_parser::write_xml_element(
std::cout, it->first, it->second,
0, settings
);
or you can create a new ptree object with the single child
ptree tmp;
tmp.add_child(it->first, it->second);
write_xml(std::cout, tmp, settings);
Live On Coliru
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
#include <fstream>
#include <iostream>
using namespace boost::property_tree;
void parse_tree(ptree& pt, std::string key)
{
std::string nkey;
auto settings = xml_parser::xml_writer_make_settings<std::string>('\t', 1);
if (!key.empty()) {
nkey = key + ".";
}
ptree::const_iterator end = pt.end();
for(ptree::iterator it = pt.begin(); it != end; ++it)
{
//if the node's id an .html filname, save the node to file
std::string id = it->second.get("<xmlattr>.id","");
if (id.find(key) != std::string::npos) {
// write the single element: (undocumented API)
boost::property_tree::xml_parser::write_xml_element(
std::cout, it->first, it->second,
0, settings
);
// or: create a new pt with the single child
std::cout << "\n==========================\n\n";
ptree tmp;
tmp.add_child(it->first, it->second);
write_xml(std::cout, tmp, settings);
}
parse_tree(it->second, nkey + it->first); //recursion
}
}
int main() {
ptree pt;
read_xml("input.txt", pt);
parse_tree(pt, "B");
}
Output:
<node id="B.html">
<subnode> child B1 </subnode>
<subnode> child B2 </subnode>
</node>
==========================
<?xml version="1.0" encoding="utf-8"?>
<node id="B.html">
<subnode> child B1 </subnode>
<subnode> child B2 </subnode>
</node>
This question already has answers here:
boost::property_tree XML pretty printing
(4 answers)
Closed 8 years ago.
I'm using Boost Property Trees to export my class-instants as XML nodes.
It works but it just puts everything in 1 line. I would like it to have indents, like:
<?xml version="1.0" encoding="utf-8"?>
<root>
<sensorconfigurations>
<configuration>
<name>SensorConfiguration1</name>
<sensorid>1</sensorid>
<signalindex>1</signalindex>
<mappingscheme>mappingscheme1</mappingscheme>
<soundpack>test1.wav</soundpack>
</configuration>
<configuration>
<name>SensorConfiguration2</name>
<sensorid>2</sensorid>
<signalindex>2</signalindex>
<mappingscheme>mappingscheme1</mappingscheme>
<soundpack>test2.wav</soundpack>
</configuration>
<configuration>
<name>SensorConfiguration3</name>
<sensorid>3</sensorid>
<signalindex>3</signalindex>
<mappingscheme>mappingscheme2</mappingscheme>
<soundpack>test3.wav</soundpack>
</configuration>
</sensorconfigurations>
</root>
Is this possible somehow? Am I missing a parameter in the write_xml method?
Here's my code:
void SensorConfigurationBank::save()
{
using boost::property_tree::ptree;
ptree pt;
for(map<string, SensorConfiguration>:: iterator it = sensorConfigurations_.begin(); it != sensorConfigurations_.end(); ++it)
{
ptree myTree;
myTree.put("name", it->second.getName());
myTree.put("sensorid", it->second.getSensorID());
myTree.put("signalindex", it->second.getsignalIndex());
MappingScheme myScheme = it->second.getMScheme();
myTree.put("mappingscheme", myScheme.getId());
SoundPack mySound = it->second.getSound();
myTree.put("soundpack", mySound.filepath_);
pt.add_child("root.sensorconfigurations.configuration", myTree);
}
write_xml("SensorConfigurationBank2.xml", pt);
}
These days, xml_writer_settings apparently takes a string type as template argument, so:
boost::property_tree::xml_writer_settings<std::string> settings('\t', 1);
write_xml(std::cout, pt, settings);
will do the trick. Full sample:
Live On Coliru
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
#include <map>
#include <iostream>
struct SoundPack {
std::string filepath_ = "soundpack.wav";
};
struct MappingScheme {
std::string getId() const { return "Id"; }
};
struct SensorConfiguration {
std::string getName() const { return "Name"; }
std::string getSensorID() const { return "SensorID"; }
std::string getsignalIndex() const { return "signalIndex"; }
SoundPack getSound() const { return {}; }
MappingScheme getMScheme() const { return {}; }
};
void save(std::map<std::string, SensorConfiguration> sensorConfigurations_)
{
using boost::property_tree::ptree;
ptree pt;
for(std::map<std::string, SensorConfiguration>:: iterator it = sensorConfigurations_.begin(); it != sensorConfigurations_.end(); ++it)
{
ptree myTree;
MappingScheme myScheme = it->second.getMScheme();
SoundPack mySound = it->second.getSound();
myTree.put("name", it->second.getName());
myTree.put("sensorid", it->second.getSensorID());
myTree.put("signalindex", it->second.getsignalIndex());
myTree.put("mappingscheme", myScheme.getId());
myTree.put("soundpack", mySound.filepath_);
pt.add_child("root.sensorconfigurations.configuration", myTree);
}
boost::property_tree::xml_writer_settings<std::string> settings('\t', 1);
write_xml(std::cout, pt, settings);
}
int main() {
save({
{ "first", SensorConfiguration {} },
{ "second", SensorConfiguration {} },
{ "third", SensorConfiguration {} },
{ "fourth", SensorConfiguration {} }
});
}
Output:
<?xml version="1.0" encoding="utf-8"?>
<root>
<sensorconfigurations>
<configuration>
<name>Name</name>
<sensorid>SensorID</sensorid>
<signalindex>signalIndex</signalindex>
<mappingscheme>Id</mappingscheme>
<soundpack>soundpack.wav</soundpack>
</configuration>
<configuration>
<name>Name</name>
<sensorid>SensorID</sensorid>
<signalindex>signalIndex</signalindex>
<mappingscheme>Id</mappingscheme>
<soundpack>soundpack.wav</soundpack>
</configuration>
<configuration>
<name>Name</name>
<sensorid>SensorID</sensorid>
<signalindex>signalIndex</signalindex>
<mappingscheme>Id</mappingscheme>
<soundpack>soundpack.wav</soundpack>
</configuration>
<configuration>
<name>Name</name>
<sensorid>SensorID</sensorid>
<signalindex>signalIndex</signalindex>
<mappingscheme>Id</mappingscheme>
<soundpack>soundpack.wav</soundpack>
</configuration>
</sensorconfigurations>
</root>
I am using boost 1.53.0, I have implemented a small demo using boost for subgraph.
I need to export the subgraph information in the graphml file, while exporting it will create all the nodes in the parent graph but not able to hold the information about it's subraphs.
so please help me if there is any way to hold information about subgraph?.
My implementation is exporting as follows:
enter code here
<?xml version="1.0" encoding="UTF-8"?>
<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
<graph id="G" edgedefault="undirected" parse.nodeids="free"
parse.edgeids="canonical" parse.order="nodesfirst">
<node id="n0">
</node>
<node id="n1">
</node>
<node id="n2">
</node>
<node id="n3">
</node>
<node id="n4">
</node>
<node id="n5">
</node>
<edge id="e0" source="n0" target="n1">
</edge>
<edge id="e1" source="n1" target="n2">
</edge>
<edge id="e2" source="n1" target="n3">
</edge>
<edge id="e3" source="n4" target="n1">
</edge>
<edge id="e4" source="n4" target="n5">
</edge>
<edge id="e5" source="n5" target="n3">
</edge>
<edge id="e6" source="n2" target="n5">
</edge>
</graph>
</graphml>
Actully the nodes n0,n1,n2 are members of subgraph G1 and n4,n5 are members of subgrph G2.
G0 is main parent graph.
Following is the way to deal with above problem. This problem is solved by combining the use of dynamic properties from boost and also using bundled properties from boost.
this code works for boost 1_53_0.
Reference property map is used for storing the properties of boost subgraph.
#include <QtCore/QCoreApplication>
#include <boost/config.hpp>
#include <iostream>
#include <algorithm>
#include <boost/graph/adjacency_list.hpp>
#include <boost/property_map/property_map.hpp>
#include <string>
#include <boost/graph/subgraph.hpp>
#include <QMap>
using namespace std;
using namespace boost;
enum graph_IDproperty_t
{
graph_IDproperty
};
namespace boost
{
BOOST_INSTALL_PROPERTY(graph,IDproperty);
}
struct GraphProperties {
std::string strName;
std::string id;
};
typedef boost::subgraph<boost::adjacency_list< boost::listS,
boost::vecS,
boost::bidirectionalS,
boost::property<boost::vertex_index_t, int , property<boost::vertex_color_t, boost::default_color_type > > ,
boost::property<boost::edge_index_t,int, property<boost::edge_color_t , default_color_type> > ,
boost::property<graph_IDproperty_t,GraphProperties > > >
Graph;
Graph gMainGraph;
typedef QMap<Graph*,GraphProperties*> mapGraphToProperty;
mapGraphToProperty getMap(Graph& graph);
void graphMapRecur(mapGraphToProperty& map, Graph& graph);
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Graph& subG = gMainGraph.create_subgraph();
Graph& subG1 = gMainGraph.create_subgraph();
boost::ref_property_map<Graph*, GraphProperties>
graph_propt1(boost::get_property(subG1,graph_IDproperty));
graph_propt1[&subG1].id = "SubG1";
cout<<graph_propt1[&subG1].id<<endl;
boost::ref_property_map<Graph*, GraphProperties>
graph_propt(boost::get_property(subG,graph_IDproperty));
graph_propt[&subG].id = "SubG";
cout<<graph_propt[&subG].id<<endl;
boost::ref_property_map<Graph*, GraphProperties>
graph_proptMain(boost::get_property(gMainGraph,graph_IDproperty));
graph_proptMain[&gMainGraph].id = "gMain";
cout<<graph_proptMain[&gMainGraph].id<<endl;
mapGraphToProperty map = getMap(gMainGraph);
boost::ref_property_map<Graph*, GraphProperties>
graph_proptMain1(*(map.value(&gMainGraph)));
boost::ref_property_map<Graph*, GraphProperties>
graph_proptsubG(*(map.value(&subG)));
boost::ref_property_map<Graph*, GraphProperties>
graph_proptsubG1(*(map.value(&subG1)));
cout<<"Main G Value : "<<graph_proptMain1[&gMainGraph].id<<endl;
cout<<"Sub G Value : "<<graph_proptsubG[&subG].id<<endl;
cout<<"Sub G1 Value : "<<graph_proptsubG1[&subG1].id<<endl;
cout<<"Map Value Main: "<<(map.value(&gMainGraph))<<endl;
cout<<"Map Value SubG: "<<(map.value(&subG))<<endl;
cout<<"Map Value SubG1b: "<<(map.value(&subG1))<<endl;
return a.exec();
}
mapGraphToProperty getMap(Graph &graph)
{
mapGraphToProperty map;
graphMapRecur(map,graph);
return map;
}
void graphMapRecur(mapGraphToProperty &map, Graph &graph)
{
Graph::children_iterator itrSubgraph, itrSubgraph_end;
for (boost::tie(itrSubgraph, itrSubgraph_end) = (graph).children(); itrSubgraph != itrSubgraph_end; ++itrSubgraph)
{
graphMapRecur(map,(*itrSubgraph));
}
GraphProperties* gp = &(get_property(graph,graph_IDproperty));
map.insert(&graph,gp);
cout<<"Recurrr"<<endl;
}
I have just discovered boost::property_tree, which seems the perfect answer to my problem. I wrote a small test program to extract specific data from an xml file. I have used the example provided in the documentation as a guide.
The xml file: test.xml:
<section>
<GROUP>
<g_name>ABC</g_name>
<fields>
<row>
<name>A</name>
<datatype>string</datatype>
<field_size>6</field_size>
<value>ABC</value>
</row>
<row>
<name>B</name>
<datatype>integer</datatype>
<field_size>5</field_size>
<value>00107</value>
</row>
<row>
<name>C</name>
<datatype>string</datatype>
<field_size>20</field_size>
<value>LOTS OF LETTERS </value>
</row>
</fields>
</GROUP>
<GROUP>
<g_name>CDE</g_name>
<fields>
<row>
<name>A</name>
<datatype>string</datatype>
<field_size>6</field_size>
<value>CDE</value>
</row>
<row>
<name>B</name>
<datatype>integer</datatype>
<field_size>5</field_size>
<value>00100</value>
</row>
<row>
<name>F</name>
<datatype>integer</datatype>
<field_size>4</field_size>
<value>1970</value>
</row>
</fields>
</GROUP>
</section>
The code:
using boost::property_tree::ptree;
struct t_collection
{
ptree pt;
void load(const std::string &filename);
void print();
};
void t_collection::load(const std::string &filename)
{
read_xml(filename, pt);
}
void t_collection::print()
{
BOOST_FOREACH(ptree::value_type &v, pt.get_child("section.GROUP"))
BOOST_FOREACH(ptree::value_type &v, pt.get_child("section.GROUP"))
{
printf("X: %s->", v.second.data().c_str());
//prints X: ABC ->
BOOST_FOREACH(ptree::value_type &w, pt.get_child("section.GROUP.fields.row"))
printf("%s\n", w.second.data().c_str());
//prints A, string, 6, ABC - that is good for first iteration but there should be 3 iterations here
}
//then prints X: and just "" and repeats the set from the first one
}
int main()
{
try
{
t_collection t1;
t1.load("test.xml");
t1.print();
}
catch (std::exception &e)
{
std::cout << "Error: " << e.what() << "\n";
}
return 0;
}
Note: I am trying to extract the values (ABC and the inner values, like A - string - 6 - ABC, for each GROUP - and each set of "row", which I will process and then output in a different format). Please see comment in code for something I tried.
So far the best result was with: (contents inside print():
BOOST_FOREACH(ptree::value_type &z, pt.get_child("section"))
//BOOST_FOREACH(ptree::value_type &v, pt.get_child("section.GROUP"))
{
printf("X: %s->", pt.get<std::string>("section.GROUP.g_mame", "default").c_str());
//prints X: ABC ->
BOOST_FOREACH(ptree::value_type &w, pt.get_child("section.GROUP.fields.row"))
{
printf("%s\n", pt.get<std::string>("section.GROUP.fields.row.name", "name").c_str());
printf("%s\n", pt.get<std::string>("section.GROUP.fields.row.datatype", "type").c_str());
printf("%s\n", pt.get<std::string>("section.GROUP.fields.row.field_size", "size").c_str());
printf("%s\n", pt.get<std::string>("section.GROUP.fields.row.value", "value").c_str());
}
}
//prints x: default->A, string, 6, ABC (3 times) then repeat identically
I can't get the data from more than one record ! Please help, give me a suggestion - what am I doing wrong ?
Thank you.
You are missing a level in your iteration. You need to iterate over the elements that have multiple children with the same name.
std::pair<ptree::const_assoc_iterator, ptree::const_assoc_iterator>
r(pt.get_child("section").equal_range("GROUP"));
for (ptree::const_assoc_iterator i(r.first); i != r.second; ++i) {
// Do something with each group.
}
Repeat as appropriate as you descend the tree.
I have to use class Matrix4x4 from some 3rd party library, and I need to serialize it.
1. Is it ok to create header(3rdparty_serialization.h) that will contain all serialization that is needed for 3rd party libraries, like Matrix4x4:
namespace boost {
namespace serialization {
template<class Archive>
void serialize(Archive & ar, Matrix4x4 & m, const unsigned int version)
{
for(size_t i = 0; i < 4;++i)
for(size_t j = 0; j < 4;++j)
{
auto& e = m[i][j];
ar & BOOST_SERIALIZATION_NVP(e);
}
}
} // namespace serialization
} // namespace boost
2. Is this definition of function "serialize" for Matrix4x4 correct?
3. How to customize formatting of Matrix4x4 serialization?
Now, I have output:
<m class_id="2" tracking_level="0" version="0">
<e>1</e>
<e>0</e>
<e>0</e>
<e>0</e>
<e>0</e>
<e>1</e>
<e>0</e>
<e>0</e>
<e>0</e>
<e>0</e>
<e>1</e>
<e>0</e>
<e>0</e>
<e>0</e>
<e>0</e>
<e>1</e>
</m>
I want something like this:
<m class_id="2" tracking_level="0" version="0">
<e>1;0;0;0</e>
<e>0;1;0;0</e>
<e>0;0;1;0</e>
<e>0;0;0;1</e>
</m>
or other more compact and readable form.
There a couple of ways to do this. The easiest way would be to make a special verision of serialize for xml_archive. This would keep the change from infecting other archive types. Try something like:
template<>
void save(boost::archive::xml_archive & ar, const Matrix4x4 & m, const unsigned int version)
{
std::string e;
for(size_t i = 0; i < 4;++i){
for(size_t j = 0; j < 4;++j)
{
e += std::string(m[i][j]);
e += ';';
}
}
ar << BOOST_SERIALIZATION_NVP(e)
}
// similar for load
Robert Ramey
1. Yes.
2. Yes, assuming Matrix is not within a namespace.
3. You could try serializing std::strings instead of individual elements. However, this is a bit wasteful since you will need to format and parse the strings. Also not optimal for size if you want to use e.g. binary_[io]archive.