Is it possible to generate non-blocking calls with dbusxx-xml2cpp? - c++

I would like to generate C++ headers using dbusxx-xml2cpp where some methods are non-blocking, e.g. using invoke_method_noreply instead of invoke_method. Is this possible?
For example the following XML:
<?xml version="1.0" encoding="UTF-8" ?>
<node name="/me/MyService">
<interface name="me.MyService">
<method name="MyMethod">
<arg direction="in" type="s" name="argument"/>
</method>
</interface>
</node>
Would generate (partly):
void MyMethod(const std::string& argument)
{
::DBus::CallMessage call;
::DBus::MessageIter wi = call.writer();
wi << argument;
call.member("MyMethod");
::DBus::Message ret = invoke_method (call);
}
But I would like to have something like:
void MyMethod(const std::string& argument)
{
::DBus::CallMessage call;
::DBus::MessageIter wi = call.writer();
wi << argument;
call.member("MyMethod");
bool ret = invoke_method_noreply (call);
}

Use the annotation org.freedesktop.DBus.Method.NoReply"
Example XML:
<node>
<interface name="org.test.example">
<method name="NoReplyMethod">
<arg name="data" direction="in" type="i"/>
<annotation name="org.freedesktop.DBus.Method.NoReply" value="true"/>
</method>
</interface>
</node>
Generated Code:
void NoReplyMethod(const int32_t& data)
{
::DBus::CallMessage call;
::DBus::MessageIter wi = call.writer();
wi << data;
call.member("NoReplyMethod");
assert (invoke_method_noreply (call));
}

Related

How to set c++ boost graphml node and edge id?

I am using the Boost graph to store a set of nodes and edges and then write it to a graphml format. Whatever I do, I cannot find a way to access or set the node id (n0, n1) or edge id (e0) attributes.
It seems to be automatically set.
Is there a way to access and set it manually ?
<?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">
<key id="key0" for="node" attr.name="id" attr.type="int" />
<key id="key1" for="edge" attr.name="length" attr.type="double" />
<key id="key2" for="edge" attr.name="max_speed" attr.type="double" />
<key id="key3" for="node" attr.name="name" attr.type="string" />
<key id="key4" for="edge" attr.name="name" attr.type="string" />
<key id="key5" for="edge" attr.name="source" attr.type="int" />
<key id="key6" for="node" attr.name="station" attr.type="boolean" />
<key id="key7" for="edge" attr.name="target" attr.type="int" />
<key id="key8" for="node" attr.name="theta" attr.type="double" />
<key id="key9" for="node" attr.name="x" attr.type="double" />
<key id="key10" for="node" attr.name="y" attr.type="double" />
<graph id="G" edgedefault="directed" parse.nodeids="canonical" parse.edgeids="canonical" parse.order="nodesfirst">
<node id="n0">
<data key="key0">10000</data>
<data key="key3">node1</data>
<data key="key6">0</data>
<data key="key8">0</data>
<data key="key9">6.95279e-310</data>
<data key="key10">0</data>
</node>
<node id="n1">
<data key="key0">10001</data>
<data key="key3">node1</data>
<data key="key6">0</data>
<data key="key8">0</data>
<data key="key9">6.95279e-310</data>
<data key="key10">0</data>
</node>
<edge id="e0" source="n0" target="n1">
<data key="key1">6.95279e-310</data>
<data key="key2">150</data>
<data key="key4"></data>
<data key="key5">-127787376</data>
<data key="key7">21994</data>
</edge>
</graph>
</graphml>
My graph
typedef typename boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS,
GpNode, GpEdge>
DirectedGraph;
Where GpNode and GpEdge are custom class definitions.
Thanks in advance
write_graphml takes a dynamic_properties. Let's configure that:
Live On Coliru
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graphml.hpp>
struct GpNode {
int id;
std::string name;
bool station;
double theta;
double x;
double y;
};
struct GpEdge {
double length;
double max_speed;
std::string name;
int source;
int target;
};
using DirectedGraph = boost::adjacency_list<boost::vecS, boost::vecS,
boost::directedS, GpNode, GpEdge>;
int main() {
std::ifstream ifs("input.xml");
DirectedGraph g;
auto n0 = add_vertex(
GpNode{
10000, // id
"node1", // name
0, // station
0, // theta
6.95279e-310, // x
0, // y
}, g);
auto n1 = add_vertex(
GpNode{
10001, // id
"node1", // name
0, // station
0, // theta
6.95279e-310, // x
0, // y
}, g);
/*auto e0 = */add_edge(n0, n1,
GpEdge{
6.95279e-310, // length
150, // max_speed
"", // name
-127787376, // source
21994, // target
}, g);
auto vindex = get(&GpNode::id, g);
boost::dynamic_properties dp;
//dp.property("node_id", vindex);
dp.property("id", vindex);
dp.property("name", get(&GpNode::name, g));
dp.property("station", get(&GpNode::station, g));
dp.property("theta", get(&GpNode::theta, g));
dp.property("x", get(&GpNode::x, g));
dp.property("y", get(&GpNode::y, g));
dp.property("length", get(&GpEdge::length, g));
dp.property("max_speed", get(&GpEdge::max_speed, g));
dp.property("name", get(&GpEdge::name, g));
dp.property("source", get(&GpEdge::source, g));
dp.property("target", get(&GpEdge::target, g));
boost::write_graphml(std::cout, g, dp);
}
Prints
<?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">
<key id="key0" for="node" attr.name="id" attr.type="int" />
<key id="key1" for="edge" attr.name="length" attr.type="double" />
<key id="key2" for="edge" attr.name="max_speed" attr.type="double" />
<key id="key3" for="node" attr.name="name" attr.type="string" />
<key id="key4" for="edge" attr.name="name" attr.type="string" />
<key id="key5" for="edge" attr.name="source" attr.type="int" />
<key id="key6" for="node" attr.name="station" attr.type="boolean" />
<key id="key7" for="edge" attr.name="target" attr.type="int" />
<key id="key8" for="node" attr.name="theta" attr.type="double" />
<key id="key9" for="node" attr.name="x" attr.type="double" />
<key id="key10" for="node" attr.name="y" attr.type="double" />
<graph id="G" edgedefault="directed" parse.nodeids="free" parse.edgeids="canonical" parse.order="nodesfirst">
<node id="n0">
<data key="key0">10000</data>
<data key="key3">node1</data>
<data key="key6">0</data>
<data key="key8">0</data>
<data key="key9">6.95279e-310</data>
<data key="key10">0</data>
</node>
<node id="n1">
<data key="key0">10001</data>
<data key="key3">node1</data>
<data key="key6">0</data>
<data key="key8">0</data>
<data key="key9">6.95279e-310</data>
<data key="key10">0</data>
</node>
<edge id="e0" source="n0" target="n1">
<data key="key1">6.95279e-310</data>
<data key="key2">150</data>
<data key="key4"></data>
<data key="key5">-127787376</data>
<data key="key7">21994</data>
</edge>
</graph>
</graphml>
Mmm. That took a while. But now I see. I know that write_graphviz_dp assumes node_id is the node id property, but as you can see, I tried and it didn't help
Docs To The Rescue
But, wait, docs show a second overload that also takes VertexIndexMap. Let's.... try that?
boost::write_graphml(std::cout, g, vindex, dp);
Now it prints
Live On Coliru
<?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">
<key id="key0" for="node" attr.name="id" attr.type="int" />
<key id="key1" for="edge" attr.name="length" attr.type="double" />
<key id="key2" for="edge" attr.name="max_speed" attr.type="double" />
<key id="key3" for="node" attr.name="name" attr.type="string" />
<key id="key4" for="edge" attr.name="name" attr.type="string" />
<key id="key5" for="edge" attr.name="source" attr.type="int" />
<key id="key6" for="node" attr.name="station" attr.type="boolean" />
<key id="key7" for="edge" attr.name="target" attr.type="int" />
<key id="key8" for="node" attr.name="theta" attr.type="double" />
<key id="key9" for="node" attr.name="x" attr.type="double" />
<key id="key10" for="node" attr.name="y" attr.type="double" />
<graph id="G" edgedefault="directed" parse.nodeids="free" parse.edgeids="canonical" parse.order="nodesfirst">
<node id="n10000">
<data key="key0">10000</data>
<data key="key3">node1</data>
<data key="key6">0</data>
<data key="key8">0</data>
<data key="key9">6.95279e-310</data>
<data key="key10">0</data>
</node>
<node id="n10001">
<data key="key0">10001</data>
<data key="key3">node1</data>
<data key="key6">0</data>
<data key="key8">0</data>
<data key="key9">6.95279e-310</data>
<data key="key10">0</data>
</node>
<edge id="e0" source="n10000" target="n10001">
<data key="key1">6.95279e-310</data>
<data key="key2">150</data>
<data key="key4"></data>
<data key="key5">-127787376</data>
<data key="key7">21994</data>
</edge>
</graph>
</graphml>
That's likely as close as you'll get with it. Changing the id type to std::string doesn't prevent the "n" prefix. (I suppose it's to allow edges to have id's colliding with nodes without problems?)

boost::property_tree XML issue

I am fighting with getting values from the following XML structure:
<ActionMaps version="1" optionsVersion="2" rebindVersion="2" profileName="full_export">
<CustomisationUIHeader label="full_export" description="" image="">
<devices>
<keyboard instance="1"/>
<mouse instance="1"/>
</devices>
<categories>
<category label="#ui_CCSpaceFlight"/>
<category label="#ui_CGLightControllerDesc"/>
<category label="#ui_CCFPS"/>
<category label="#ui_CCEVA"/>
<category label="#ui_CGOpticalTracking"/>
<category label="#ui_CGInteraction"/>
</categories>
</CustomisationUIHeader>
<options type="keyboard" instance="1" Product="Tastatur {6F1D2B61-D5A0-11CF-BFC7-444553540000}">
<flight_move_yaw exponent="1.5"/>
</options>
<modifiers />
<actionmap name="spaceship_general">
<action name="v_close_all_doors">
<rebind input="kb1_0"/>
</action>
<action name="v_cooler_throttle_down">
<rebind input="kb1_6"/>
</action>
<action name="v_cooler_throttle_up">
<rebind input="kb1_5"/>
</action>
<action name="v_eject">
<rebind input="kb1_1"/>
</action>
...
The code I am using is
const std::string XML_PATH = std::string(fqn_file.mb_str());
boost::property_tree::ptree pt1;
boost::property_tree::read_xml( XML_PATH, pt1 );
// Traverse property tree example
BOOST_FOREACH(boost::property_tree::ptree::value_type const& node,
pt1.get_child( "ActionMaps.actionmap" ) ) {
boost::property_tree::ptree subtree = node.second;
if ( node.first == "actionmap" ) {
BOOST_FOREACH(boost::property_tree::ptree::value_type const& v,
subtree.get_child( "" ) ) {
std::string label = v.first;
if ( label != "<xmlattr>" ) {
std::string value = subtree.get<std::string>( label );
wxString m_value(value);
std::cout << label << ": " << value << std::endl;
wxString m_label(label);
wxLogMessage("DEBUG -> Label = " + m_label + " Value = " + value);
}
}
}
}
If I go for 'action' or 'label' the values are empty which seems to be normal. But how I can access name (#name) from action and input (#input) from rebind?
I expect to get e.g. the pair of values 'v_close_all_doors' and 'kb1_0'. Of course I need a second iteration for the second value but for the first I need to understand how to access these values.
I gave up with boost::property_tree as its seems to be designed to handle simple XML structures only. Made more progress using RapidXML

Parsing nested xml with boost

I have an xml which I like to read into my program, I've seen a lot of exmaples how to read xml using property tree from boost, however I couldn't make it work for the nested xml that I have:
<?xml version="1.0" encoding="UTF-8"?>
<document version="1.3.0">
<chunk>
<sensors>
<sensor id="0" label="unknown" type="frame">
<resolution width="2056" height="2464"/>
<property name="fixed" value="0"/>
<calibration type="frame" class="adjusted">
<resolution width="2056" height="2464"/>
<fx>7349.85579147491</fx>
<fy>7349.85579147491</fy>
<cx>1028</cx>
<cy>1232</cy>
<p1>0.000308132854297239</p1>
<p2>-0.000521332855614243</p2>
</calibration>
</sensor>
</sensors>
<cameras>
<camera id="0" label="img0000.png" sensor_id="0" enabled="1">
<transform>1.0000000000000000e+000 0.0000000000000000e+000 0.0000000000000000e+000 0.0000000000000000e+000 0.0000000000000000e+000 -1.0000000000000000e+000 -1.2246467991473532e-016 0.0000000000000000e+000 0.0000000000000000e+000 1.2246467991473532e-016 -1.0000000000000000e+000 0.0000000000000000e+000 0.0000000000000000e+000 0.0000000000000000e+000 0.0000000000000000e+000 1.0000000000000000e+000</transform>
</camera>
<camera id="1" label="img0011.png" sensor_id="0" enabled="1">
<transform>9.8183676675341047e-001 -2.7892274662900951e-002 -1.8766615162393202e-001 1.3502780959894856e+000 -2.8076662610258110e-002 -9.9960436765543659e-001 1.6760611099915072e-003 -8.8020303958543274e-003 -1.8763865398120155e-001 3.6234208013954891e-003 -9.8223144235654503e-001 -1.1015316085201440e-001 0.0000000000000000e+000 0.0000000000000000e+000 0.0000000000000000e+000 1.0000000000000000e+000</transform>
</camera>
</cameras>
<reference>LOCAL_CS["Local Coordinates (m)",LOCAL_DATUM["Local Datum",0],UNIT["metre",1,AUTHORITY["EPSG","9001"]]]</reference>
<region>
<center>-5.1216167685514069e-002 -7.0600760442627708e-001 -6.9904047240845895e+000</center>
<size>2.1074647950629393e+000 1.5533586459855240e+000 1.0253878730038792e+000</size>
<R>-9.6011547075389880e-001 2.7340714563038887e-001 5.8539008680217816e-002 -2.6221584379471408e-001 -9.5313222127937347e-001 1.5093647677772853e-001 9.7062526662174770e-002 1.2956659089939432e-001 9.8680867671533157e-001</R>
</region>
<settings>
<property name="accuracy_tiepoints" value="1"/>
<property name="accuracy_cameras" value="10"/>
<property name="accuracy_cameras_ypr" value="2"/>
<property name="accuracy_markers" value="0.005"/>
<property name="accuracy_scalebars" value="0.001"/>
<property name="accuracy_projections" value="0.1"/>
</settings>
</chunk>
</document>
I'm only interested in reading the cameras node and their attributes, and I've used the following code for that, but it doesn't work:
using namespace std;
using namespace boost;
using namespace boost::property_tree;
const ptree& empty_ptree() {
static ptree t;
return t;
}
int main()
{
ptree tree;
read_xml(XML_PATH1, tree);
tree = tree.get_child("document.chunk", empty_ptree());
const ptree & formats = tree.get_child("cameras.camera", empty_ptree());
BOOST_FOREACH(const ptree::value_type & f, formats)
{
string at = f.first + ".<xmlattr>";
const ptree & attributes = f.second.get_child("<xmlattr>", empty_ptree());
cout << "Extracting attributes from " << at << ":" << endl;
BOOST_FOREACH(const ptree::value_type &v, attributes)
{
cout << "First: " << v.first.data() << " Second: " << v.second.data() << endl;
}
}
}
so, for each camera you want to iterate over each attribute, don't you ?
if yes, then you need to use equal_range() instead of get_child(); the latter returns a single child, the former a range of associative iterators pointing to all childs with the given key.
so, use get_child() to get document.chunk.cameras, use equal_range('camera') to get all cameras and for each camera use equal_range('xmlattr') to traverse its attributes.

QT DOMXml - Change the name of a node [duplicate]

This question already has answers here:
Edit Value of a QDomElement?
(6 answers)
Closed 6 years ago.
I am working on a QT Project and part of that is a reconstruction of an XML file. I was able to make most of the needed changes with QDom but I can't find how to rename a node.
So the old XML file looks like ..
<root>
<window name="" ..>
<element x="" y=""/>
<element1 a="" b=""/>
...
</window>
..
..
<window name="">
<element x="" y=""/>
<element1 a="" b=""/>
...
</window>
</root>
How can i change the XML so that the new one will have < group > instead of < window >?
So at the end it needs to look like..
<root>
<group name="" ..>
<element x="" y=""/>
<element1 a="" b=""/>
...
</group>
..
..
<group name="">
<element x="" y=""/>
<element1 a="" b=""/>
...
</group>
</root>
Adding some more info...
Here is the code I use to read the <window> nodes, delete some based on the visibility (comes from a list) and I need to change <window> to <group> for the remaining nodes.
QFile oldXml("file.xml");
oldXml.open(QIODevice::ReadOnly);
QDomDocument doc;
doc.setContent(&oldXml);
QDomNodeList nodes = doc.elementsByTagName("window");
// Remove Window nodes based on visibility
insize = nodes.length();
for ( int i = 0; i < insize; i++ ) {
QDomNode node = nodes.at(i-dels);
if ( (list2[i] == "0") | (list2[i]=="") ) {
node.parentNode().removeChild(node);
dels=dels+1;
} else {
// Here is where i need to change the node name from <window> to e.g. <group>
}
}
You could use setTagName and maybe setAttribute if you want to set a value for the name attribute.
With the following example, myxml.xml is converted to xmlout.xml
Note#1: this is just an example: we're replacing only the first node.
Note#2: in this example, we're using two different files. Depending on your design, you could use the same or not.
myxml.xml
<root>
<window name="">
<element x="" y=""/>
<element1 a="" b=""/>
</window>
<window name="">
<element x="" y=""/>
<element1 a="" b=""/>
</window>
</root>
xmlout.xml
<root>
<group name="value">
<element y="" x=""/>
<element1 a="" b=""/>
</group>
<window name="">
<element y="" x=""/>
<element1 a="" b=""/>
</window>
</root>
main.cpp
#include <iostream>
#include <QtXml>
#include <QFile>
int main(int argc, char *argv[])
{
QDomDocument doc;
// Load xml file as raw data
QFile inFile(":myxml.xml");
if (!inFile.open(QIODevice::ReadOnly ))
{
std::cerr << "Error - inFile: " << inFile.errorString().toStdString();
return 1;
}
// Set data into the QDomDocument before processing
doc.setContent(&inFile);
// Get element in question
QDomElement root = doc.documentElement();
QDomElement nodeTag = root.firstChildElement("window");
nodeTag.setTagName("group");
nodeTag.setAttribute("name","value");
inFile.close();
// Save the modified data
QFile outFile("xmlout.xml");
if (!outFile.open(QIODevice::WriteOnly ))
{
// Error while loading file
std::cerr << "Error - outFile: " << outFile.errorString().toStdString();
return 1;
}
QTextStream stream;
stream.setDevice(&outFile);
stream.setCodec("UTF-8");
doc.save(stream,4);
outFile.close();
return 0;
}
I did not see any straight API function to rename the element. API is allowing to change value but not name.
There is another round about way.
Create an element, for example:
QDomElement group = doc.createElement("group");
use "QDomNode's replacechild" function.
QDomNode QDomNode::replaceChild(const QDomNode &newChild, const QDomNode &oldChild)
ex:
QDomNode dNode = node.replaceChild(group,oldNode);

Adding subtree to boost::property_tree element

What I want is this:
<tree>
<objects>
<object id="12345678">
<AdditionalInfo>
<Owner>Mr. Heik</Owner>
<Health>37/100</Health>
</AdditionalInfo>
</object>
</objects>
</tree>
What I get is this:
<tree>
<objects>
<object id="12345678"/>
<AdditionalInfo>
<Owner>Mr. Heik</Owner>
<Health>37/100</Health>
</AdditionalInfo>
</objects>
</tree>
What I tried is this:
using boost::property_tree::ptree;
ptree pt;
boost::property_tree::ptree nodeObject;
nodeObject.put("object.<xmlattr>.id", 12345678);
boost::property_tree::ptree nodeInfo;
nodeInfo.put("Owner", "Mr. Heik");
nodeInfo.put("Health", "37/100");
// Put everything together
nodeObject.put_child("AdditionalInfo", nodeInfo);
pt.add_child("tree.objects", nodeObject);
write_xml("output.xml", pt);
I tried to get the desired result by using put/add/add_child/etc. but without success. Which boost-functions do I have to use?
This line :
nodeObject.put("object.<xmlattr>.id", 12345678);
Is adding a new child to the subpath "object" of the current node with the given attribute.
Just set your attribute on the Node:
nodeObject.put("<xmlattr>.id", 12345678);
And add the node directly to the correct path in your tree:
pt.add_child("tree.objects.object", nodeObject);
Final code :
ptree pt;
boost::property_tree::ptree nodeObject;
nodeObject.put("<xmlattr>.id", 12345678);
boost::property_tree::ptree nodeInfo;
nodeInfo.put("Owner", "Mr. Heik");
nodeInfo.put("Health", "37/100");
nodeObject.put_child("AdditionalInfo", nodeInfo);
pt.add_child("tree.objects.object", nodeObject);
write_xml("output.xml", pt);
Output :
<?xml version="1.0" encoding="utf-8"?>
<tree>
<objects>
<object id="12345678">
<AdditionalInfo>
<Owner>Mr. Heik</Owner>
<Health>37/100</Health>
</AdditionalInfo>
</object>
</objects>
</tree>