XmlWriter.cpp
Go to the documentation of this file.
1/*
2* This file is part of ArmarX.
3*
4* ArmarX is free software; you can redistribute it and/or modify
5* it under the terms of the GNU General Public License version 2 as
6* published by the Free Software Foundation.
7*
8* ArmarX is distributed in the hope that it will be useful, but
9* WITHOUT ANY WARRANTY; without even the implied warranty of
10* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11* GNU General Public License for more details.
12*
13* You should have received a copy of the GNU General Public License
14* along with this program. If not, see <http://www.gnu.org/licenses/>.
15*
16* @package ArmarX::
17* @author Christian Mandery (christian.mandery at kit dot edu)
18* @date 2014
19* @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20* GNU General Public License
21*/
22
23#include "XmlWriter.h"
24
25#include <SimoxUtility/algorithm/string/string_tools.h>
26
31
37
38using namespace armarx::statechartio;
39using namespace armarx::statechartmodel;
40
41XmlWriter::XmlWriter(const armarx::VariantInfoPtr& variantInfo) : variantInfo(variantInfo)
42{
43}
44
45void
46XmlWriter::serialize(StateCPtr state, const QMap<QString, StateTreeNodePtr>& uuidToNodeMap)
47{
48 document.clear();
49
50 document.append_node(buildXmlDeclaration());
51
52 rapidxml::xml_node<>* rootNode = document.allocate_node(rapidxml::node_element, "State");
53
54 rootNode->append_attribute(document.allocate_attribute("version", "1.2"));
55 rootNode->append_attribute(
56 document.allocate_attribute("name", cloneQString(state->getStateName())));
57 rootNode->append_attribute(document.allocate_attribute("uuid", cloneQString(state->getUUID())));
58 rootNode->append_attribute(document.allocate_attribute(
59 "width", cloneQString(QString::number(state->getSize().width()))));
60 rootNode->append_attribute(document.allocate_attribute(
61 "height", cloneQString(QString::number(state->getSize().height()))));
62 rootNode->append_attribute(document.allocate_attribute(
63 "type", cloneQString(statechartmodel::State::StateTypeToString(state->getType()))));
64
65 const QString& description = state->getDescription();
66
67 if (!description.isEmpty())
68 {
69 rootNode->append_node(buildDescription(description));
70 }
71
72 rootNode->append_node(buildParameterList("InputParameters", state->getInputParameters()));
73 rootNode->append_node(buildParameterList("OutputParameters", state->getOutputParameters()));
74 rootNode->append_node(buildParameterList("LocalParameters", state->getLocalParameters()));
75 rootNode->append_node(buildSubstateList(state->getSubstates()));
76 rootNode->append_node(buildEventList(state->getOutgoingEvents()));
77
78 TransitionCPtr startStateTransition = state->getStartTransition();
79
80 if (startStateTransition->destinationState)
81 {
82 rootNode->append_node(buildStartState(startStateTransition));
83 }
84 rootNode->append_node(buildTransitionList(state->getTransitions(), uuidToNodeMap));
85
86 document.append_node(rootNode);
87}
88
89QString
90XmlWriter::getXmlString(bool indent) const
91{
92 std::string s;
93 rapidxml::print(std::back_inserter(s), document, indent ? 0 : rapidxml::print_no_indenting);
94
95 return QString::fromStdString(s);
96}
97
98void
100{
101 substateNode = document.allocate_node(rapidxml::node_element, "LocalState");
102 substateNode->append_attribute(
103 document.allocate_attribute("refuuid", cloneQString(localState->getClassUUID())));
104 substateNode->append_attribute(document.allocate_attribute(
105 "left", cloneQString(QString::number(localState->getTopLeft().x()))));
106 substateNode->append_attribute(document.allocate_attribute(
107 "top", cloneQString(QString::number(localState->getTopLeft().y()))));
108 substateNode->append_attribute(document.allocate_attribute(
109 "boundingSquareSize", cloneQString(QString::number(localState->getBoundingSquareSize()))));
110}
111
112void
114{
115 substateNode = document.allocate_node(rapidxml::node_element, "RemoteState");
116 substateNode->append_attribute(
117 document.allocate_attribute("refuuid", cloneQString(remoteState->getClassUUID())));
118 substateNode->append_attribute(
119 document.allocate_attribute("proxyName", cloneQString(remoteState->proxyName)));
120 substateNode->append_attribute(document.allocate_attribute(
121 "left", cloneQString(QString::number(remoteState->getTopLeft().x()))));
122 substateNode->append_attribute(document.allocate_attribute(
123 "top", cloneQString(QString::number(remoteState->getTopLeft().y()))));
124 substateNode->append_attribute(document.allocate_attribute(
125 "boundingSquareSize", cloneQString(QString::number(remoteState->getBoundingSquareSize()))));
126}
127
128void
130{
131 substateNode = document.allocate_node(rapidxml::node_element, "DynamicRemoteState");
132 substateNode->append_attribute(
133 document.allocate_attribute("refuuid", cloneQString(dynamicRemoteState->getClassUUID())));
134 substateNode->append_attribute(document.allocate_attribute(
135 "left", cloneQString(QString::number(dynamicRemoteState->getTopLeft().x()))));
136 substateNode->append_attribute(document.allocate_attribute(
137 "top", cloneQString(QString::number(dynamicRemoteState->getTopLeft().y()))));
138 substateNode->append_attribute(document.allocate_attribute(
139 "boundingSquareSize",
140 cloneQString(QString::number(dynamicRemoteState->getBoundingSquareSize()))));
141}
142
143void
145{
146 substateNode = document.allocate_node(rapidxml::node_element, "EndState");
147 substateNode->append_attribute(
148 document.allocate_attribute("event", cloneQString(endState->getEventName())));
149 substateNode->append_attribute(document.allocate_attribute(
150 "left", cloneQString(QString::number(endState->getTopLeft().x()))));
151 substateNode->append_attribute(document.allocate_attribute(
152 "top", cloneQString(QString::number(endState->getTopLeft().y()))));
153 substateNode->append_attribute(document.allocate_attribute(
154 "boundingSquareSize", cloneQString(QString::number(endState->getBoundingSquareSize()))));
155}
156
158XmlWriter::buildDescription(const QString& description)
159{
160 return document.allocate_node(rapidxml::node_element, "Description", cloneQString(description));
161}
162
164XmlWriter::buildEventList(const EventList& eventList)
165{
166 rapidxml::xml_node<>* rootNode = document.allocate_node(rapidxml::node_element, "Events");
167
168 for (EventList::const_iterator i = eventList.begin(); i != eventList.end(); ++i)
169 {
170 statechartmodel::EventPtr event = *i;
171
172 rapidxml::xml_node<>* eventNode = document.allocate_node(rapidxml::node_element, "Event");
173 eventNode->append_attribute(document.allocate_attribute("name", cloneQString(event->name)));
174
175 if (!event->description.isEmpty())
176 {
177 eventNode->append_node(buildDescription(event->description));
178 }
179
180 rootNode->append_node(eventNode);
181 }
182
183 return rootNode;
184}
185
186rapidxml::xml_node<>*
187XmlWriter::buildParameterList(const QString& tagName,
189{
190 rapidxml::xml_node<>* rootNode =
191 document.allocate_node(rapidxml::node_element, cloneQString(tagName));
192
193 for (armarx::statechartmodel::StateParameterMap::const_iterator i = parameterMap.begin();
194 i != parameterMap.end();
195 ++i)
196 {
197 QString parameterName = i.key();
198 statechartmodel::StateParameterPtr parameter = i.value();
199
200 rapidxml::xml_node<>* parameterNode =
201 document.allocate_node(rapidxml::node_element, "Parameter");
202
203 parameterNode->append_attribute(
204 document.allocate_attribute("name", cloneQString(parameterName)));
205 parameterNode->append_attribute(
206 document.allocate_attribute("type", cloneQString(parameter->type)));
207 parameterNode->append_attribute(document.allocate_attribute(
208 "docType",
209 cloneQString(QString::fromStdString(
210 variantInfo->getNestedHumanNameFromBaseName(parameter->type.toStdString())))));
211 parameterNode->append_attribute(
212 document.allocate_attribute("optional", parameter->optional ? "yes" : "no"));
213
214 if (!parameter->description.isEmpty())
215 {
216 parameterNode->append_node(buildDescription(parameter->description));
217 }
218
219 for (auto j = parameter->profileDefaultValues.constBegin();
220 j != parameter->profileDefaultValues.constEnd();
221 ++j)
222 {
223 rapidxml::xml_node<>* profileDefaultValueNode =
224 document.allocate_node(rapidxml::node_element, "DefaultValue");
225 QString profileName = j.key();
226
227 if (profileName.toStdString() != StatechartProfiles::GetRootName())
228 {
229 profileDefaultValueNode->append_attribute(
230 document.allocate_attribute("profile", cloneQString(profileName)));
231 }
232
233 if (j.value().first)
234 {
235 JSONObjectPtr jsonObject = new JSONObject();
236 jsonObject->serializeIceObject(j.value().first);
237 profileDefaultValueNode->append_attribute(
238 document.allocate_attribute("value", cloneQString(j.value().second)));
239 profileDefaultValueNode->append_attribute(
240 document.allocate_attribute("docValue",
241 cloneQString(QString::fromStdString(
242 escapeString(j.value().first->toString())))));
243 parameterNode->append_node(profileDefaultValueNode);
244 }
245 else if (j.value().second.size() != 0)
246 {
247 profileDefaultValueNode->append_attribute(
248 document.allocate_attribute("value", cloneQString(j.value().second)));
249 parameterNode->append_node(profileDefaultValueNode);
250 }
251 }
252
253 rootNode->append_node(parameterNode);
254 }
255
256 return rootNode;
257}
258
259std::string
260XmlWriter::escapeString(std::string str)
261{
262 str = simox::alg::replace_all(str, "\\", "\\\\");
263 str = simox::alg::replace_all(str, "\r", "\\r");
264 str = simox::alg::replace_all(str, "\n", "\\n");
265 return str;
266}
267
268rapidxml::xml_node<>*
269XmlWriter::buildParameterMappingList(
270 const armarx::statechartmodel::ParameterMappingList& parameterMappingList,
271 const QString& mappingName)
272{
273
274 rapidxml::xml_node<>* rootNode = document.allocate_node(
275 rapidxml::node_element, document.allocate_string(mappingName.toUtf8().data()));
276
277 for (ParameterMappingList::const_iterator j = parameterMappingList.begin();
278 j != parameterMappingList.end();
279 ++j)
280 {
281 statechartmodel::ParameterMappingPtr parameterMapping = *j;
282
283 rapidxml::xml_node<>* parameterMappingNode =
284 document.allocate_node(rapidxml::node_element, "ParameterMapping");
285
286 QString mappingSourceString;
287
288 mappingSourceString =
289 QString::fromStdString(PM::MappingSourceToString(parameterMapping->source));
290
291 parameterMappingNode->append_attribute(
292 document.allocate_attribute("sourceType", cloneQString(mappingSourceString)));
293 parameterMappingNode->append_attribute(
294 document.allocate_attribute("from", cloneQString(parameterMapping->sourceKey)));
295 parameterMappingNode->append_attribute(
296 document.allocate_attribute("to", cloneQString(parameterMapping->destinationKey)));
297
298 for (auto j = parameterMapping->profileValues.constBegin();
299 j != parameterMapping->profileValues.constEnd();
300 ++j)
301 {
302 rapidxml::xml_node<>* profileDefaultValueNode =
303 document.allocate_node(rapidxml::node_element, "DefaultValue");
304 QString profileName = j.key();
305
306 if (profileName.toStdString() != StatechartProfiles::GetRootName())
307 {
308 profileDefaultValueNode->append_attribute(
309 document.allocate_attribute("profile", cloneQString(profileName)));
310 }
311
312 profileDefaultValueNode->append_attribute(
313 document.allocate_attribute("value", cloneQString(j.value())));
314 parameterMappingNode->append_node(profileDefaultValueNode);
315 }
316
317
318 rootNode->append_node(parameterMappingNode);
319 }
320
321 return rootNode;
322}
323
324rapidxml::xml_node<>*
325XmlWriter::buildStartState(TransitionCPtr startStateTransition)
326{
327 rapidxml::xml_node<>* rootNode = document.allocate_node(rapidxml::node_element, "StartState");
328
329 rootNode->append_attribute(document.allocate_attribute(
330 "substateName", cloneQString(startStateTransition->destinationState->getInstanceName())));
331
332 rapidxml::xml_node<>* parameterMappingsNode = buildParameterMappingList(
333 startStateTransition->mappingToNextStatesInput, "ParameterMappings");
334 rootNode->append_node(parameterMappingsNode);
335
336 // Support points
337 rapidxml::xml_node<>* supportPointsNode =
338 document.allocate_node(rapidxml::node_element, "SupportPoints");
339 auto supportPoints = startStateTransition->supportPoints.toPointList();
340 for (QList<QPointF>::const_iterator j = supportPoints.begin(); j != supportPoints.end(); ++j)
341 {
342 QPointF supportPoint = *j;
343
344 rapidxml::xml_node<>* supportPointNode =
345 document.allocate_node(rapidxml::node_element, "SupportPoint");
346 supportPointNode->append_attribute(
347 document.allocate_attribute("posX", cloneQString(QString::number(supportPoint.x()))));
348 supportPointNode->append_attribute(
349 document.allocate_attribute("posY", cloneQString(QString::number(supportPoint.y()))));
350
351 supportPointsNode->append_node(supportPointNode);
352 }
353
354 rootNode->append_node(supportPointsNode);
355
356 return rootNode;
357}
358
359rapidxml::xml_node<>*
360XmlWriter::buildSubstateList(const StateInstanceMap& substateMap)
361{
362 rapidxml::xml_node<>* rootNode = document.allocate_node(rapidxml::node_element, "Substates");
363
364 for (StateInstanceMap::const_iterator i = substateMap.begin(); i != substateMap.end(); ++i)
365 {
366 QString substateName = i.key();
367 StateInstancePtr substate = i.value();
368
369 substate->accept(*this);
370 substateNode->prepend_attribute(
371 document.allocate_attribute("name", cloneQString(substateName)));
372 rootNode->append_node(substateNode);
373 }
374
375 return rootNode;
376}
377
378rapidxml::xml_node<>*
379XmlWriter::buildTransitionList(const CTransitionList& transitionList,
380 const QMap<QString, StateTreeNodePtr>& uuidToNodeMap)
381{
382 rapidxml::xml_node<>* rootNode = document.allocate_node(rapidxml::node_element, "Transitions");
383
384 for (CTransitionList::const_iterator i = transitionList.begin(); i != transitionList.end(); ++i)
385 {
386 TransitionCPtr transition = *i;
387 // Create transition node
388 rapidxml::xml_node<>* transitionNode =
389 document.allocate_node(rapidxml::node_element, "Transition");
390 transitionNode->append_attribute(document.allocate_attribute(
391 "from", cloneQString(transition->sourceState->getInstanceName())));
392 if (transition->transitionUserCode && transition->destinationState)
393 {
394 transitionNode->append_attribute(
395 document.allocate_attribute("transitionCodeEnabled", "1"));
396 if (transition->destinationState->getStateClass())
397 {
398 auto it =
399 uuidToNodeMap.find(transition->destinationState->getStateClass()->getUUID());
400
401 if (it != uuidToNodeMap.end())
402 {
403 const StateTreeNodePtr node = it.value();
404 if (node)
405 {
406 transitionNode->append_attribute(document.allocate_attribute(
407 "toClass", cloneQString(node->getState()->getStateName())));
408 transitionNode->append_attribute(document.allocate_attribute(
409 "toGroup", cloneQString(node->getGroup()->getName())));
410 transitionNode->append_attribute(document.allocate_attribute(
411 "toPackage", cloneQString(node->getGroup()->getPackageName())));
412 }
413 }
414 if (transition->sourceState)
415 {
416 if (transition->sourceState->getStateClass())
417 {
418 it =
419 uuidToNodeMap.find(transition->sourceState->getStateClass()->getUUID());
420
421 if (it != uuidToNodeMap.end())
422 {
423 const StateTreeNodePtr node = it.value();
424 if (node)
425 {
426 transitionNode->append_attribute(document.allocate_attribute(
427 "fromClass", cloneQString(node->getState()->getStateName())));
428 transitionNode->append_attribute(document.allocate_attribute(
429 "fromGroup", cloneQString(node->getGroup()->getName())));
430 transitionNode->append_attribute(document.allocate_attribute(
431 "fromPackage",
432 cloneQString(node->getGroup()->getPackageName())));
433 }
434 }
435 }
436 else
437 {
438 throw LocalException() << ("Could not find source stateclass of instance " +
439 transition->sourceState->getInstanceName() +
440 "! Please open all Remote States in the "
441 "Statechart Editor before saving.");
442 }
443 }
444 }
445 else
446 {
447 throw LocalException()
448 << ("Could not find destination stateclass of instance " +
449 transition->destinationState->getInstanceName() +
450 "! Please open all Remote States in the Statechart Editor before saving.");
451 }
452 }
453
454 if (transition->destinationState)
455 {
456 transitionNode->append_attribute(document.allocate_attribute(
457 "to", cloneQString(transition->destinationState->getInstanceName())));
458 }
459
460 transitionNode->append_attribute(
461 document.allocate_attribute("eventName", cloneQString(transition->eventName)));
462
463 // Parameter mappings
464 rapidxml::xml_node<>* parameterMappingsNode =
465 buildParameterMappingList(transition->mappingToNextStatesInput, "ParameterMappings");
466 transitionNode->append_node(parameterMappingsNode);
467 parameterMappingsNode = buildParameterMappingList(transition->mappingToParentStatesLocal,
468 "ParameterMappingsToParentsLocal");
469 transitionNode->append_node(parameterMappingsNode);
470 parameterMappingsNode = buildParameterMappingList(transition->mappingToParentStatesOutput,
471 "ParameterMappingsToParentsOutput");
472 transitionNode->append_node(parameterMappingsNode);
473
474
475 // Support points
476 rapidxml::xml_node<>* supportPointsNode =
477 document.allocate_node(rapidxml::node_element, "SupportPoints");
478 auto supportPoints = transition->supportPoints.toPointList();
479 for (QList<QPointF>::const_iterator j = supportPoints.begin(); j != supportPoints.end();
480 ++j)
481 {
482 QPointF supportPoint = *j;
483
484 rapidxml::xml_node<>* supportPointNode =
485 document.allocate_node(rapidxml::node_element, "SupportPoint");
486 supportPointNode->append_attribute(document.allocate_attribute(
487 "posX", cloneQString(QString::number(supportPoint.x()))));
488 supportPointNode->append_attribute(document.allocate_attribute(
489 "posY", cloneQString(QString::number(supportPoint.y()))));
490
491 supportPointsNode->append_node(supportPointNode);
492 }
493
494 transitionNode->append_node(supportPointsNode);
495
496 rootNode->append_node(transitionNode);
497 }
498
499 return rootNode;
500}
501
502rapidxml::xml_node<>*
503XmlWriter::buildXmlDeclaration()
504{
505 rapidxml::xml_node<>* node = document.allocate_node(rapidxml::node_declaration);
506 node->append_attribute(document.allocate_attribute("version", "1.0"));
507 node->append_attribute(document.allocate_attribute("encoding", "utf-8"));
508
509 return node;
510}
511
512char*
513XmlWriter::cloneQString(const QString& string)
514{
515 // We need to clone all strings because the QByteArrays created be toUtf8() are destroyed immediately after leaving the scope.
516 return document.allocate_string(string.toUtf8());
517}
std::string str(const T &t)
static std::string MappingSourceToString(MappingSource mappingSource)
static std::string GetRootName()
void visitDynamicRemoteState(armarx::statechartmodel::DynamicRemoteStateCPtr dynamicRemoteState) override
void visitLocalState(armarx::statechartmodel::LocalStateCPtr localState) override
Definition XmlWriter.cpp:99
QString getXmlString(bool indent=true) const
Builds the XML document for the state object that has been handled by serialize() before.
Definition XmlWriter.cpp:90
void visitEndState(armarx::statechartmodel::EndStateCPtr endState) override
XmlWriter(const VariantInfoPtr &variantInfo)
Definition XmlWriter.cpp:41
void visitRemoteState(armarx::statechartmodel::RemoteStateCPtr remoteState) override
void serialize(armarx::statechartmodel::StateCPtr state, const QMap< QString, StateTreeNodePtr > &uuidToNodeMap=QMap< QString, StateTreeNodePtr >())
Builds XML data structures for serialization of the given state object.
Definition XmlWriter.cpp:46
static QString StateTypeToString(eStateType type)
Definition State.cpp:1294
xml_node< Ch > * allocate_node(node_type type, const Ch *name=nullptr, const Ch *value=nullptr, std::size_t name_size=0, std::size_t value_size=0)
Allocates a new node from the pool, and optionally assigns name and value to it.
Definition rapidxml.hpp:446
xml_attribute< Ch > * allocate_attribute(const Ch *name=nullptr, const Ch *value=nullptr, std::size_t name_size=0, std::size_t value_size=0)
Allocates a new attribute from the pool, and optionally assigns name and value to it.
Definition rapidxml.hpp:492
Class representing a node of XML document.
void append_node(xml_node< Ch > *child)
Appends a new child node.
void append_attribute(xml_attribute< Ch > *attribute)
Appends a new attribute to the node.
std::string toUtf8(QString const &qstring)
QMap< QString, StateParameterPtr > StateParameterMap
std::shared_ptr< StateInstance > StateInstancePtr
std::shared_ptr< const LocalState > LocalStateCPtr
Definition XmlWriter.h:50
std::shared_ptr< StateParameter > StateParameterPtr
QList< ParameterMappingPtr > ParameterMappingList
Definition XmlWriter.h:49
std::shared_ptr< const State > StateCPtr
Definition XmlWriter.h:45
std::shared_ptr< Event > EventPtr
Definition XmlWriter.h:46
std::shared_ptr< const Transition > TransitionCPtr
Definition Transition.h:91
std::shared_ptr< const EndState > EndStateCPtr
Definition XmlWriter.h:52
QList< EventPtr > EventList
Definition XmlWriter.h:47
QList< TransitionCPtr > CTransitionList
Definition State.h:51
std::shared_ptr< const DynamicRemoteState > DynamicRemoteStateCPtr
std::shared_ptr< const RemoteState > RemoteStateCPtr
Definition XmlWriter.h:51
std::shared_ptr< ParameterMapping > ParameterMappingPtr
Definition XmlWriter.h:48
QMap< QString, StateInstancePtr > StateInstanceMap
Definition State.h:52
std::shared_ptr< VariantInfo > VariantInfoPtr
Definition VariantInfo.h:39
IceInternal::Handle< JSONObject > JSONObjectPtr
Definition JSONObject.h:34
std::shared_ptr< StateTreeNode > StateTreeNodePtr
OutIt print(OutIt out, const xml_node< Ch > &node, int flags=0)
Prints XML to given output iterator.
@ node_element
An element node. Name contains element name. Value contains text of first data node.
Definition rapidxml.hpp:151
@ node_declaration
A declaration node. Name and value are empty. Declaration parameters (version, encoding and standalon...
Definition rapidxml.hpp:155
const int print_no_indenting
Printer flag instructing the printer to suppress indenting of XML. See print() function.
This file contains rapidxml printer implementation.