YARP
Yet Another Robot Platform
XMLReaderFileV1.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2006-2021 Istituto Italiano di Tecnologia (IIT)
3 * SPDX-License-Identifier: BSD-3-Clause
4 */
5
7
14
15#include <yarp/os/LogStream.h>
16#include <yarp/os/Network.h>
17#include <yarp/os/Property.h>
18
19#include <algorithm>
20#include <iterator>
21#include <sstream>
22#include <string>
23#include <tinyxml.h>
24#include <utility>
25#include <vector>
26
27#define SYNTAX_ERROR(line) yFatal() << "Syntax error while loading" << curr_filename << "at line" << line << "."
28#define SYNTAX_WARNING(line) yWarning() << "Invalid syntax while loading" << curr_filename << "at line" << line << "."
29
30// BUG in TinyXML, see
31// https://sourceforge.net/tracker/?func=detail&aid=3567726&group_id=13559&atid=113559
32// When this bug is fixed upstream we can enable this
33#define TINYXML_UNSIGNED_INT_BUG 0
34
36{
37public:
39 virtual ~Private();
40
44
49
57
62
64 std::string filename;
65 std::string path;
66#ifdef USE_DTD
68#endif
69
71 std::string curr_filename;
72 unsigned int minorVersion;
73 unsigned int majorVersion;
74};
75
76
78 parent(p),
79 minorVersion(0),
80 majorVersion(0)
81{
82 verbose_output = false;
83}
84
86
88{
89 filename = fileName;
90#ifdef WIN32
91 std::replace(filename.begin(), filename.end(), '/', '\\');
92#endif
93
94 curr_filename = fileName;
95#ifdef WIN32
96 path = filename.substr(0, filename.rfind("\\"));
97#else // WIN32
98 path = filename.substr(0, filename.rfind('/'));
99#endif //WIN32
100
101 yDebug() << "Reading file" << filename.c_str();
102 auto* doc = new TiXmlDocument(filename.c_str());
103 if (!doc->LoadFile()) {
104 SYNTAX_ERROR(doc->ErrorRow()) << doc->ErrorDesc();
106 }
107
108 if (!doc->RootElement()) {
109 SYNTAX_ERROR(doc->Row()) << "No root element.";
111 }
112
113#ifdef USE_DTD
114 for (TiXmlNode* childNode = doc->FirstChild(); childNode != 0; childNode = childNode->NextSibling()) {
115 if (childNode->Type() == TiXmlNode::TINYXML_UNKNOWN) {
116 if (dtd.parse(childNode->ToUnknown(), curr_filename)) {
117 break;
118 }
119 }
120 }
121
122 if (!dtd.valid()) {
123 SYNTAX_WARNING(doc->Row()) << "No DTD found. Assuming version yarprobotinterfaceV1.0";
124 dtd.setDefault();
126 }
127
128 if (dtd.type != RobotInterfaceDTD::DocTypeRobot) {
129 SYNTAX_WARNING(doc->Row()) << "Expected document of type" << DocTypeToString(RobotInterfaceDTD::DocTypeRobot)
130 << ". Found" << DocTypeToString(dtd.type);
131 }
132
133 if (dtd.majorVersion != 1 || dtd.minorVersion != 0) {
134 SYNTAX_WARNING(doc->Row()) << "Only yarprobotinterface DTD version 1.0 is supported";
135 }
136#endif
137
138 yarp::robotinterface::XMLReaderResult result = readRobotTag(doc->RootElement());
139 delete doc;
140
141 // yDebug() << robot;
142
143 return result;
144}
145
147{
148 curr_filename = " XML runtime string ";
149 auto* doc = new TiXmlDocument();
150 if (!doc->Parse(xmlString.c_str())) {
151 SYNTAX_ERROR(doc->ErrorRow()) << doc->ErrorDesc();
153 }
154
155 if (!doc->RootElement()) {
156 SYNTAX_ERROR(doc->Row()) << "No root element.";
158 }
159
160 yarp::robotinterface::XMLReaderResult result = readRobotTag(doc->RootElement());
161 delete doc;
162
163 return result;
164}
165
166
168{
170 result.parsingIsSuccessful = true;
171
172 if (robotElem->ValueStr() != "robot") {
173 SYNTAX_ERROR(robotElem->Row()) << "Root element should be \"robot\". Found" << robotElem->ValueStr();
175 }
176
177 if (robotElem->QueryStringAttribute("name", &result.robot.name()) != TIXML_SUCCESS) {
178 SYNTAX_ERROR(robotElem->Row()) << R"("robot" element should contain the "name" attribute)";
180 }
181
182#if TINYXML_UNSIGNED_INT_BUG
183 if (robotElem->QueryUnsignedAttribute("build", &robot.build()) != TIXML_SUCCESS) {
184 // No build attribute. Assuming build="0"
185 SYNTAX_WARNING(robotElem->Row()) << "\"robot\" element should contain the \"build\" attribute [unsigned int]. Assuming 0";
186 }
187#else
188 int tmp;
189 if (robotElem->QueryIntAttribute("build", &tmp) != TIXML_SUCCESS || tmp < 0) {
190 // No build attribute. Assuming build="0"
191 SYNTAX_WARNING(robotElem->Row()) << R"("robot" element should contain the "build" attribute [unsigned int]. Assuming 0)";
192 tmp = 0;
193 }
194 result.robot.build() = static_cast<unsigned>(tmp);
195#endif
196
197 if (robotElem->QueryStringAttribute("portprefix", &result.robot.portprefix()) != TIXML_SUCCESS) {
198 SYNTAX_WARNING(robotElem->Row()) << R"("robot" element should contain the "portprefix" attribute. Using "name" attribute)";
199 result.robot.portprefix() = result.robot.name();
200 }
201
202 // yDebug() << "Found robot [" << robot.name() << "] build [" << robot.build() << "] portprefix [" << robot.portprefix() << "]";
203
204 for (TiXmlElement* childElem = robotElem->FirstChildElement(); childElem != nullptr; childElem = childElem->NextSiblingElement()) {
205 if (childElem->ValueStr() == "device" || childElem->ValueStr() == "devices") {
206 for (const auto& childDevice : readDevices(childElem, result)) {
207 result.robot.devices().push_back(childDevice);
208 }
209 } else {
210 for (const auto& childParam : readParams(childElem, result)) {
211 result.robot.params().push_back(childParam);
212 }
213 }
214 }
215
216 return result;
217}
218
219
222{
223 const std::string& valueStr = devicesElem->ValueStr();
224
225 if (valueStr == "device") {
226 // yDebug() << valueStr;
228 deviceList.push_back(readDeviceTag(devicesElem, result));
229 return deviceList;
230 }
231
232 if (valueStr == "devices") {
233 // "devices"
234 return readDevicesTag(devicesElem, result);
235 }
236
237 SYNTAX_ERROR(devicesElem->Row()) << R"(Expected "device" or "devices". Found)" << valueStr;
238 result.parsingIsSuccessful = false;
240}
241
244{
245 const std::string& valueStr = deviceElem->ValueStr();
246
247 if (valueStr != "device") {
248 SYNTAX_ERROR(deviceElem->Row()) << "Expected \"device\". Found" << valueStr;
249 result.parsingIsSuccessful = false;
250 }
251
253
254 if (deviceElem->QueryStringAttribute("name", &device.name()) != TIXML_SUCCESS) {
255 SYNTAX_ERROR(deviceElem->Row()) << R"("device" element should contain the "name" attribute)";
256 result.parsingIsSuccessful = false;
257 }
258
259 // yDebug() << "Found device [" << device.name() << "]";
260
261 if (deviceElem->QueryStringAttribute("type", &device.type()) != TIXML_SUCCESS) {
262 SYNTAX_ERROR(deviceElem->Row()) << R"("device" element should contain the "type" attribute)";
263 result.parsingIsSuccessful = false;
264 }
265
266 device.params().push_back(yarp::robotinterface::Param("robotName", result.robot.portprefix()));
267
268 for (TiXmlElement* childElem = deviceElem->FirstChildElement(); childElem != nullptr; childElem = childElem->NextSiblingElement()) {
269 if (childElem->ValueStr() == "action" || childElem->ValueStr() == "actions") {
270 for (const auto& childAction : readActions(childElem, result)) {
271 device.actions().push_back(childAction);
272 }
273 } else {
274 for (const auto& childParam : readParams(childElem, result)) {
275 device.params().push_back(childParam);
276 }
277 }
278 }
279
280 // yDebug() << device;
281 return device;
282}
283
286{
287 std::string filename;
288 if (devicesElem->QueryStringAttribute("file", &filename) == TIXML_SUCCESS) {
289 // yDebug() << "Found devices file [" << filename << "]";
290#ifdef WIN32
291 std::replace(filename.begin(), filename.end(), '/', '\\');
292 filename = path + "\\" + filename;
293#else // WIN32
294 filename = path + "/" + filename;
295#endif //WIN32
296 return readDevicesFile(filename, result);
297 }
298
300 for (TiXmlElement* childElem = devicesElem->FirstChildElement(); childElem != nullptr; childElem = childElem->NextSiblingElement()) {
301 for (const auto& childDevice : readDevices(childElem, result)) {
302 devices.push_back(childDevice);
303 }
304 }
305
306 return devices;
307}
308
311{
312 std::string old_filename = curr_filename;
313 curr_filename = fileName;
314
315 yDebug() << "Reading file" << fileName.c_str();
316 auto* doc = new TiXmlDocument(fileName.c_str());
317 if (!doc->LoadFile()) {
318 SYNTAX_ERROR(doc->ErrorRow()) << doc->ErrorDesc();
319 }
320
321 if (!doc->RootElement()) {
322 SYNTAX_ERROR(doc->Row()) << "No root element.";
323 }
324
325#ifdef USE_DTD
326 RobotInterfaceDTD devicesFileDTD;
327 for (TiXmlNode* childNode = doc->FirstChild(); childNode != 0; childNode = childNode->NextSibling()) {
328 if (childNode->Type() == TiXmlNode::TINYXML_UNKNOWN) {
329 if (devicesFileDTD.parse(childNode->ToUnknown(), curr_filename)) {
330 break;
331 }
332 }
333 }
334
335 if (!devicesFileDTD.valid()) {
336 SYNTAX_WARNING(doc->Row()) << "No DTD found. Assuming version yarprobotinterfaceV1.0";
337 devicesFileDTD.setDefault();
339 }
340
341 if (devicesFileDTD.type != RobotInterfaceDTD::DocTypeDevices) {
342 SYNTAX_ERROR(doc->Row()) << "Expected document of type" << DocTypeToString(RobotInterfaceDTD::DocTypeDevices)
343 << ". Found" << DocTypeToString(devicesFileDTD.type);
344 }
345
346 if (devicesFileDTD.majorVersion != dtd.majorVersion) {
347 SYNTAX_ERROR(doc->Row()) << "Trying to import a file with a different yarprobotinterface DTD version";
348 }
349#endif
350
351 yarp::robotinterface::DeviceList devices = readDevicesTag(doc->RootElement(), result);
352 delete doc;
353 curr_filename = old_filename;
354 return devices;
355}
356
357
360{
361 const std::string& valueStr = paramsElem->ValueStr();
362
363 if (valueStr == "param") {
365 params.push_back(readParamTag(paramsElem, result));
366 return params;
367 }
368 if (valueStr == "group") {
370 params.push_back(readGroupTag(paramsElem, result));
371 return params;
372 }
373 if (valueStr == "paramlist") {
374 return readParamListTag(paramsElem, result);
375 }
376 if (valueStr == "subdevice") {
377 return readSubDeviceTag(paramsElem, result);
378 }
379 if (valueStr == "params") {
380 return readParamsTag(paramsElem, result);
381 }
382 SYNTAX_ERROR(paramsElem->Row()) << R"(Expected "param", "group", "paramlist", "subdevice", or "params". Found)" << valueStr;
384}
385
386
389{
390 if (paramElem->ValueStr() != "param") {
391 SYNTAX_ERROR(paramElem->Row()) << "Expected \"param\". Found" << paramElem->ValueStr();
392 result.parsingIsSuccessful = false;
393 }
394
396
397 if (paramElem->QueryStringAttribute("name", &param.name()) != TIXML_SUCCESS) {
398 SYNTAX_ERROR(paramElem->Row()) << R"("param" element should contain the "name" attribute)";
399 result.parsingIsSuccessful = false;
400 }
401
402 // yDebug() << "Found param [" << param.name() << "]";
403
404 const char* valueText = paramElem->GetText();
405 if (!valueText) {
406 SYNTAX_ERROR(paramElem->Row()) << R"("param" element should have a value [ "name" = )" << param.name() << "]";
407 } else {
408 param.value() = valueText;
409 }
410
411 // yDebug() << param;
412 return param;
413}
414
417{
418 if (groupElem->ValueStr() != "group") {
419 SYNTAX_ERROR(groupElem->Row()) << "Expected \"group\". Found" << groupElem->ValueStr();
420 result.parsingIsSuccessful = false;
421 }
422
423 yarp::robotinterface::Param group(true);
424
425 if (groupElem->QueryStringAttribute("name", &group.name()) != TIXML_SUCCESS) {
426 SYNTAX_ERROR(groupElem->Row()) << R"("group" element should contain the "name" attribute)";
427 result.parsingIsSuccessful = false;
428 }
429
430 // yDebug() << "Found group [" << group.name() << "]";
431
433 for (TiXmlElement* childElem = groupElem->FirstChildElement(); childElem != nullptr; childElem = childElem->NextSiblingElement()) {
434 for (const auto& childParam : readParams(childElem, result)) {
435 params.push_back(childParam);
436 }
437 }
438 if (params.empty()) {
439 SYNTAX_ERROR(groupElem->Row()) << "\"group\" cannot be empty";
440 }
441
442 std::string groupString;
443 for (auto& param : params) {
444 if (!groupString.empty()) {
445 groupString += " ";
446 }
447 groupString += "(" + param.name() + " " + param.value() + ")";
448 }
449
450 group.value() = groupString;
451
452 return group;
453}
454
457{
458 if (paramListElem->ValueStr() != "paramlist") {
459 SYNTAX_ERROR(paramListElem->Row()) << "Expected \"paramlist\". Found" << paramListElem->ValueStr();
460 result.parsingIsSuccessful = false;
461 }
462
465
466 if (paramListElem->QueryStringAttribute("name", &mainparam.name()) != TIXML_SUCCESS) {
467 SYNTAX_ERROR(paramListElem->Row()) << R"("paramlist" element should contain the "name" attribute)";
468 result.parsingIsSuccessful = false;
469 }
470
471 params.push_back(mainparam);
472
473 // yDebug() << "Found paramlist [" << params.at(0).name() << "]";
474
475 for (TiXmlElement* childElem = paramListElem->FirstChildElement(); childElem != nullptr; childElem = childElem->NextSiblingElement()) {
476 if (childElem->ValueStr() != "elem") {
477 SYNTAX_ERROR(childElem->Row()) << "Expected \"elem\". Found" << childElem->ValueStr();
478 }
479
481
482 if (childElem->QueryStringAttribute("name", &childParam.name()) != TIXML_SUCCESS) {
483 SYNTAX_ERROR(childElem->Row()) << R"("elem" element should contain the "name" attribute)";
484 result.parsingIsSuccessful = false;
485 }
486
487 const char* valueText = childElem->GetText();
488 if (!valueText) {
489 SYNTAX_ERROR(childElem->Row()) << R"("elem" element should have a value [ "name" = )" << childParam.name() << "]";
490 result.parsingIsSuccessful = false;
491 } else {
492 childParam.value() = valueText;
493 }
494
495 params.push_back(childParam);
496 }
497
498 if (params.empty()) {
499 SYNTAX_ERROR(paramListElem->Row()) << "\"paramlist\" cannot be empty";
500 result.parsingIsSuccessful = false;
501 }
502
503 // +1 skips the first element, that is the main param
504 for (auto it = params.begin() + 1; it != params.end(); ++it) {
505 yarp::robotinterface::Param& param = *it;
506 params.at(0).value() += (params.at(0).value().empty() ? "(" : " ") + param.name();
507 }
508 params.at(0).value() += ")";
509
510 // yDebug() << params;
511 return params;
512}
513
516{
517 if (subDeviceElem->ValueStr() != "subdevice") {
518 SYNTAX_ERROR(subDeviceElem->Row()) << "Expected \"subdevice\". Found" << subDeviceElem->ValueStr();
519 result.parsingIsSuccessful = false;
520 }
521
523
524 //FIXME Param featIdParam;
525 yarp::robotinterface::Param subDeviceParam;
526
527 //FIXME featIdParam.name() = "FeatId";
528 subDeviceParam.name() = "subdevice";
529
530 //FIXME if (subDeviceElem->QueryStringAttribute("name", &featIdParam.value()) != TIXML_SUCCESS) {
531 // SYNTAX_ERROR(subDeviceElem->Row()) << "\"subdevice\" element should contain the \"name\" attribute";
532 // }
533
534 if (subDeviceElem->QueryStringAttribute("type", &subDeviceParam.value()) != TIXML_SUCCESS) {
535 SYNTAX_ERROR(subDeviceElem->Row()) << R"("subdevice" element should contain the "type" attribute)";
536 }
537
538 //FIXME params.push_back(featIdParam);
539 params.push_back(subDeviceParam);
540
541 // yDebug() << "Found subdevice [" << params.at(0).value() << "]";
542
543 for (TiXmlElement* childElem = subDeviceElem->FirstChildElement(); childElem != nullptr; childElem = childElem->NextSiblingElement()) {
544 for (const auto& childParam : readParams(childElem, result)) {
545 params.push_back(yarp::robotinterface::Param(childParam.name(), childParam.value()));
546 }
547 }
548
549 // yDebug() << params;
550 return params;
551}
552
555{
556 //const std::string &valueStr = paramsElem->ValueStr();
557
558 std::string filename;
559 if (paramsElem->QueryStringAttribute("file", &filename) == TIXML_SUCCESS) {
560 // yDebug() << "Found params file [" << filename << "]";
561#ifdef WIN32
562 std::replace(filename.begin(), filename.end(), '/', '\\');
563 filename = path + "\\" + filename;
564#else // WIN32
565 filename = path + "/" + filename;
566#endif //WIN32
567 return readParamsFile(filename, result);
568 }
569
570 /*std::string robotName;
571 if (paramsElem->QueryStringAttribute("robot", &robotName) != TIXML_SUCCESS) {
572 SYNTAX_WARNING(paramsElem->Row()) << "\"params\" element should contain the \"robot\" attribute";
573 }
574
575 if (robotName != robot.name()) {
576 SYNTAX_WARNING(paramsElem->Row()) << "Trying to import a file for the wrong robot. Found" << robotName << "instead of" << robot.name();
577 }*/
578
579 /*
580 unsigned int build;
581#if TINYXML_UNSIGNED_INT_BUG
582 if (paramsElem->QueryUnsignedAttribute("build", &build()) != TIXML_SUCCESS) {
583 // No build attribute. Assuming build="0"
584 SYNTAX_WARNING(paramsElem->Row()) << "\"params\" element should contain the \"build\" attribute [unsigned int]. Assuming 0";
585 }
586#else
587 int tmp;
588 if (paramsElem->QueryIntAttribute("build", &tmp) != TIXML_SUCCESS || tmp < 0) {
589 // No build attribute. Assuming build="0"
590 SYNTAX_WARNING(paramsElem->Row()) << "\"params\" element should contain the \"build\" attribute [unsigned int]. Assuming 0";
591 tmp = 0;
592 }
593 build = (unsigned)tmp;
594#endif
595
596 if (build != robot.build()) {
597 SYNTAX_WARNING(paramsElem->Row()) << "Import a file for a different robot build. Found" << build << "instead of" << robot.build();
598 }
599 */
601 for (TiXmlElement* childElem = paramsElem->FirstChildElement(); childElem != nullptr; childElem = childElem->NextSiblingElement()) {
602 for (const auto & childParam : readParams(childElem, result)) {
603 params.push_back(childParam);
604 }
605 }
606
607 return params;
608}
609
612{
613 std::string old_filename = curr_filename;
614 curr_filename = fileName;
615
616 yDebug() << "Reading file" << fileName.c_str();
617 auto* doc = new TiXmlDocument(fileName.c_str());
618 if (!doc->LoadFile()) {
619 SYNTAX_ERROR(doc->ErrorRow()) << doc->ErrorDesc();
620 result.parsingIsSuccessful = false;
622 }
623
624 if (!doc->RootElement()) {
625 SYNTAX_ERROR(doc->Row()) << "No root element.";
626 result.parsingIsSuccessful = false;
628 }
629
630#ifdef USE_DTD
631 RobotInterfaceDTD paramsFileDTD;
632 for (TiXmlNode* childNode = doc->FirstChild(); childNode != 0; childNode = childNode->NextSibling()) {
633 if (childNode->Type() == TiXmlNode::TINYXML_UNKNOWN) {
634 if (paramsFileDTD.parse(childNode->ToUnknown(), curr_filename)) {
635 break;
636 }
637 }
638 }
639
640 if (!paramsFileDTD.valid()) {
641 SYNTAX_WARNING(doc->Row()) << "No DTD found. Assuming version yarprobotinterfaceV1.0";
642 paramsFileDTD.setDefault();
644 }
645
646 if (paramsFileDTD.type != RobotInterfaceDTD::DocTypeParams) {
647 SYNTAX_ERROR(doc->Row()) << "Expected document of type" << DocTypeToString(RobotInterfaceDTD::DocTypeParams)
648 << ". Found" << DocTypeToString(paramsFileDTD.type);
649 }
650
651 if (paramsFileDTD.majorVersion != dtd.majorVersion) {
652 SYNTAX_ERROR(doc->Row()) << "Trying to import a file with a different yarprobotinterface DTD version";
653 }
654
655#endif
656 yarp::robotinterface::ParamList params = readParamsTag(doc->RootElement(), result);
657 delete doc;
658 curr_filename = old_filename;
659 return params;
660}
661
664{
665 const std::string& valueStr = actionsElem->ValueStr();
666
667 if (valueStr != "action" && valueStr != "actions") {
668 SYNTAX_ERROR(actionsElem->Row()) << R"(Expected "action" or "actions". Found)" << valueStr;
669 }
670
671 if (valueStr == "action") {
673 actionList.push_back(readActionTag(actionsElem, result));
674 return actionList;
675 }
676 // "actions"
677 return readActionsTag(actionsElem, result);
678}
679
682{
683 if (actionElem->ValueStr() != "action") {
684 SYNTAX_ERROR(actionElem->Row()) << "Expected \"action\". Found" << actionElem->ValueStr();
685 }
686
688
689 if (actionElem->QueryValueAttribute<yarp::robotinterface::ActionPhase>("phase", &action.phase()) != TIXML_SUCCESS || action.phase() == yarp::robotinterface::ActionPhaseUnknown) {
690 SYNTAX_ERROR(actionElem->Row()) << R"("action" element should contain the "phase" attribute [startup|interrupt{1,2,3}|shutdown])";
691 }
692
693
694 if (actionElem->QueryValueAttribute<yarp::robotinterface::ActionType>("type", &action.type()) != TIXML_SUCCESS || action.type() == yarp::robotinterface::ActionTypeUnknown) {
695 SYNTAX_ERROR(actionElem->Row()) << R"("action" element should contain the "type" attribute [configure|calibrate|attach|abort|detach|park|custom])";
696 }
697
698 // yDebug() << "Found action [ ]";
699
700#if TINYXML_UNSIGNED_INT_BUG
701 if (actionElem->QueryUnsignedAttribute("level", &action.level()) != TIXML_SUCCESS) {
702 SYNTAX_ERROR(actionElem->Row()) << "\"action\" element should contain the \"level\" attribute [unsigned int]";
703 }
704#else
705 int tmp;
706 if (actionElem->QueryIntAttribute("level", &tmp) != TIXML_SUCCESS || tmp < 0) {
707 SYNTAX_ERROR(actionElem->Row()) << R"("action" element should contain the "level" attribute [unsigned int])";
708 }
709 action.level() = static_cast<unsigned>(tmp);
710#endif
711
712 for (TiXmlElement* childElem = actionElem->FirstChildElement(); childElem != nullptr; childElem = childElem->NextSiblingElement()) {
713 for (const auto& childParam : readParams(childElem, result)) {
714 action.params().push_back(childParam);
715 }
716 }
717
718 // yDebug() << action;
719 return action;
720}
721
724{
725 //const std::string &valueStr = actionsElem->ValueStr();
726
727 std::string filename;
728 if (actionsElem->QueryStringAttribute("file", &filename) == TIXML_SUCCESS) {
729 // yDebug() << "Found actions file [" << filename << "]";
730#ifdef WIN32
731 std::replace(filename.begin(), filename.end(), '/', '\\');
732 filename = path + "\\" + filename;
733#else // WIN32
734 filename = path + "/" + filename;
735#endif //WIN32
736 return readActionsFile(filename, result);
737 }
738
739 std::string robotName;
740 if (actionsElem->QueryStringAttribute("robot", &robotName) != TIXML_SUCCESS) {
741 SYNTAX_WARNING(actionsElem->Row()) << R"("actions" element should contain the "robot" attribute)";
742 }
743
744 if (robotName != result.robot.name()) {
745 SYNTAX_WARNING(actionsElem->Row()) << "Trying to import a file for the wrong robot. Found" << robotName << "instead of" << result.robot.name();
746 }
747
748 unsigned int build;
749#if TINYXML_UNSIGNED_INT_BUG
750 if (actionsElem->QueryUnsignedAttribute("build", &build()) != TIXML_SUCCESS) {
751 // No build attribute. Assuming build="0"
752 SYNTAX_WARNING(actionsElem->Row()) << "\"actions\" element should contain the \"build\" attribute [unsigned int]. Assuming 0";
753 }
754#else
755 int tmp;
756 if (actionsElem->QueryIntAttribute("build", &tmp) != TIXML_SUCCESS || tmp < 0) {
757 // No build attribute. Assuming build="0"
758 SYNTAX_WARNING(actionsElem->Row()) << R"("actions" element should contain the "build" attribute [unsigned int]. Assuming 0)";
759 tmp = 0;
760 }
761 build = static_cast<unsigned>(tmp);
762#endif
763
764 if (build != result.robot.build()) {
765 SYNTAX_WARNING(actionsElem->Row()) << "Import a file for a different robot build. Found" << build << "instead of" << result.robot.build();
766 }
767
769 for (TiXmlElement* childElem = actionsElem->FirstChildElement(); childElem != nullptr; childElem = childElem->NextSiblingElement()) {
770 for (const auto& childAction : readActions(childElem, result)) {
771 actions.push_back(childAction);
772 }
773 }
774
775 return actions;
776}
777
780{
781 std::string old_filename = curr_filename;
782 curr_filename = fileName;
783
784 yDebug() << "Reading file" << fileName.c_str();
785 auto* doc = new TiXmlDocument(fileName.c_str());
786 if (!doc->LoadFile()) {
787 SYNTAX_ERROR(doc->ErrorRow()) << doc->ErrorDesc();
788 }
789
790 if (!doc->RootElement()) {
791 SYNTAX_ERROR(doc->Row()) << "No root element.";
792 }
793
794#ifdef USE_DTD
795 RobotInterfaceDTD actionsFileDTD;
796 for (TiXmlNode* childNode = doc->FirstChild(); childNode != 0; childNode = childNode->NextSibling()) {
797 if (childNode->Type() == TiXmlNode::TINYXML_UNKNOWN) {
798 if (actionsFileDTD.parse(childNode->ToUnknown(), curr_filename)) {
799 break;
800 }
801 }
802 }
803
804 if (!actionsFileDTD.valid()) {
805 SYNTAX_WARNING(doc->Row()) << "No DTD found. Assuming version yarprobotinterfaceV1.0";
806 actionsFileDTD.setDefault();
808 }
809
810 if (actionsFileDTD.type != RobotInterfaceDTD::DocTypeActions) {
811 SYNTAX_ERROR(doc->Row()) << "Expected document of type" << DocTypeToString(RobotInterfaceDTD::DocTypeActions)
812 << ". Found" << DocTypeToString(actionsFileDTD.type);
813 }
814
815 if (actionsFileDTD.majorVersion != dtd.majorVersion) {
816 SYNTAX_ERROR(doc->Row()) << "Trying to import a file with a different yarprobotinterface DTD version";
817 }
818
819#endif
820 yarp::robotinterface::ActionList actions = readActionsTag(doc->RootElement(), result);
821 delete doc;
822 curr_filename = old_filename;
823 return actions;
824}
825
827 const yarp::os::Searchable& /*config*/,
828 bool verb)
829{
830 mPriv->verbose_output = verb;
831 return mPriv->readRobotFromFile(filename);
832}
833
835 const yarp::os::Searchable& /*config*/,
836 bool verb)
837{
838 mPriv->verbose_output = verb;
839 return mPriv->readRobotFromString(xmlString);
840}
841
843 mPriv(new Private(this))
844{
845}
846
848{
849 delete mPriv;
850}
#define yDebug(...)
Definition: Log.h:270
#define SYNTAX_ERROR(line)
#define SYNTAX_WARNING(line)
A base class for nested structures that can be searched.
Definition: Searchable.h:56
unsigned int & level()
Definition: Action.cpp:102
ActionPhase & phase()
Definition: Action.cpp:92
ActionList & actions()
Definition: Device.cpp:270
std::string & type()
Definition: Device.cpp:260
std::string & name()
Definition: Device.cpp:255
std::string & name()
Definition: Param.cpp:80
std::string & value()
Definition: Param.cpp:85
bool parse(TiXmlUnknown *unknownNode, const std::string &curr_filename)
std::string & portprefix()
Definition: Robot.cpp:520
DeviceList & devices()
Definition: Robot.cpp:562
ParamList & params()
Definition: Robot.cpp:557
std::string & name()
Definition: Robot.cpp:510
unsigned int & build()
Definition: Robot.cpp:515
Result of the parsing of yarp::robotinterface::XMLReader.
Definition: XMLReader.h:26
bool parsingIsSuccessful
True if the parsing was successful, false otherwise.
Definition: XMLReader.h:38
Robot robot
If parsingIsSuccessful is true, contains a valid robot instance.
Definition: XMLReader.h:43
static XMLReaderResult ParsingFailed()
Definition: XMLReader.h:28
yarp::robotinterface::Param readParamTag(TiXmlElement *paramElem, yarp::robotinterface::XMLReaderResult &result)
yarp::robotinterface::Action readActionTag(TiXmlElement *actionElem, yarp::robotinterface::XMLReaderResult &result)
yarp::robotinterface::XMLReaderResult readRobotFromString(const std::string &xmlString)
yarp::robotinterface::DeviceList readDevices(TiXmlElement *devicesElem, yarp::robotinterface::XMLReaderResult &result)
yarp::robotinterface::ParamList readParamListTag(TiXmlElement *paramListElem, yarp::robotinterface::XMLReaderResult &result)
yarp::robotinterface::ActionList readActionsTag(TiXmlElement *actionsElem, yarp::robotinterface::XMLReaderResult &result)
yarp::robotinterface::ActionList readActions(TiXmlElement *actionsElem, yarp::robotinterface::XMLReaderResult &result)
yarp::robotinterface::ParamList readParams(TiXmlElement *paramsElem, yarp::robotinterface::XMLReaderResult &result)
yarp::robotinterface::Device readDeviceTag(TiXmlElement *deviceElem, yarp::robotinterface::XMLReaderResult &result)
yarp::robotinterface::DeviceList readDevicesTag(TiXmlElement *devicesElem, yarp::robotinterface::XMLReaderResult &result)
yarp::robotinterface::ParamList readParamsFile(const std::string &fileName, yarp::robotinterface::XMLReaderResult &result)
yarp::robotinterface::DeviceList readDevicesFile(const std::string &fileName, yarp::robotinterface::XMLReaderResult &result)
yarp::robotinterface::Param readGroupTag(TiXmlElement *groupElem, yarp::robotinterface::XMLReaderResult &result)
yarp::robotinterface::XMLReaderResult readRobotFromFile(const std::string &fileName)
yarp::robotinterface::ParamList readParamsTag(TiXmlElement *paramsElem, yarp::robotinterface::XMLReaderResult &result)
yarp::robotinterface::XMLReaderResult readRobotTag(TiXmlElement *robotElem)
yarp::robotinterface::ParamList readSubDeviceTag(TiXmlElement *subDeviceElem, yarp::robotinterface::XMLReaderResult &result)
yarp::robotinterface::ActionList readActionsFile(const std::string &fileName, yarp::robotinterface::XMLReaderResult &result)
yarp::robotinterface::XMLReaderResult getRobotFromString(const std::string &xmlString, const yarp::os::Searchable &config, bool verbose=false) override
yarp::robotinterface::XMLReaderResult getRobotFromFile(const std::string &filename, const yarp::os::Searchable &config, bool verbose=false) override
std::string DocTypeToString(RobotInterfaceDTD::DocType doctype)
std::vector< robotinterface::Action > ActionList
Definition: Types.h:31
std::vector< robotinterface::Param > ParamList
Definition: Types.h:30
std::vector< robotinterface::Device > DeviceList
Definition: Types.h:32